Easymock: Issue Mocking void DAO method - Unexpected method call - easymock

Found a workaround. See solution at the bottom
Ok I have been in EasyMock jail all day and I need some help getting out.
I have a void save() method I am mocking out.
public void save(PurchaseOrder po);
PurchaseOrder is an abstract class that has two children
USPurchaseOrder
CAPurchaseOrder
Here's my code in the JUnit test
MyDAO myDAO = createMock(MyDAO.class);
PurchaseOrder usPurchaseOrder = new USPurchaseOrder(msgUS);
myDAO.save(usPurchaseOrder);
expectLastCall().atLeastOnce();
PurchaseOrder caPurchaseOrder = new CAPurchaseOrder(msgCA);
myDAO.save(caPurchaseOrder);
expectLastCall().atLeastOnce();
replay(myDAO);
//execute code that uses DAO
I get the following error: Unexpected method call MyDAO.save(USPurchaseOrder#1a70b8):
The only problem here is that the DAO signature does not require a USPurchaseOrder, only a PurchaseOrder, which is what I am passing in.
Even doing this produces the same error
myDAO.save(new USPurchaseOrder(msgUS));
What am I doing wrong?
Workaround
Ok, I kept plugging away at this and while I don't understand why I am getting the error, I added the anyObject() to the code to get it to work.
MyDAO myDAO = createMock(MyDAO.class);
myDAO.save(anyObject(OrderRequest.class));
myDAO.save(anyObject(OrderRequest.class));
replay(myDAO);
//execute code that uses DAO

For matching method calls EasyMock uses equals() for method parameters. You should take it into account. So my guess is that you have not implemented equals() in your USPurchaseOrder and the default Object.equals() behavior is used, that compares whether the instances of USPurchaseOrder are the same, which are apparently not.

Related

EasyMock 3.2: How to address public variables in a mocked class?

I'm trying to mock an open-source class. That class uses a number of public variables instead of get methods. I need to have the mocked class return another mocked class when that variable is accessed, but I'm not sure how. Here's an example:
SolrQueryRequest request = createNiceMock(SolrQueryRequest.class);
...
replay(request);
ResponseBuilder builder = createNiceMock(ResponseBuilder.class);
expect(builder.req).andReturn(request); // Throws exception
replay(builder);
The above example, however, throws the exception java.lang.IllegalStateException: no last call on a mock available on the builder.req line. Any idea how I can do this? Please note I don't have the option of refactoring the mocked classes.
Well, after playing around with it more I discovered it was pretty easy:
myBuilder.req = request;
Now when my class under test accesses the myBuilder.req variable, it is correctly set to my mocked SolrQueryRequest.

Mocking a final method with PowerMock + EasyMock

I'm trying to mock a call to the final method ResourceBundle.getString(). With PowerMock 1.4.12 and EasyMock 3.1, the call is not being mocked; instead, the "real" method is called.
My test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(ResourceBundle.class)
public class TestSuite {
#Before
public void setUp() throws Exception {
ResourceBundle resourceBundleMock = PowerMock.createNiceMock(ResourceBundle.class);
expect(resourceBundleMock.getString(BundleConstants.QUEUE)).andReturn("Queue");
PowerMock.replay(resourceBundleMock);
beanBeingTested.setMessages(resourceBundleMock);
}
...
}
Code in BeanBeingTested:
private ResourceBundle messages;
...
String label = messages.getString(BundleConstants.QUEUE);
Error message:
java.util.MissingResourceException: Can't find resource for bundle $java.util.ResourceBundle$$EnhancerByCGLIB$$e4a02557, key Queue
at java.util.ResourceBundle.getObject(ResourceBundle.java:384)
at java.util.ResourceBundle.getString(ResourceBundle.java:344)
at com.yoyodyne.BeanBeingTested.setUpMenus(BeanBeingTested.java:87)
When I step through the test case, the debugger shows the type of beanBeingTested.messages as "EasyMock for class java.util.ResourceBundle", so the mock is injected correctly. (Also, there's no error on the call to getString() within the expect() call during set up).
With a plain mock instead of a nice mock, I get the following error:
java.lang.AssertionError:
Unexpected method call handleGetObject("Queue"):
getString("Queue"): expected: 1, actual: 0
Any idea what I'm doing wrong?
Thanks.
You are creating an instance using EasyMock. Instead, when working with static methods, you must mock the class (using PowerMock).
It should work like that (tested with EasyMock 3.0 and PowerMock 1.5, though):
#RunWith(PowerMockRunner.class)
#PrepareForTest(ResourceBundle.class)
public class TestSuite {
#Before
public void setUp() throws Exception {
// mock the class for one method only
PowerMock.mockStaticNice(ResourceBundle.class, "getString");
// define mock-behaviour on the class, when calling the static method
expect(ResourceBundle.getString(BundleConstants.QUEUE)).andReturn("Queue");
// start the engine
PowerMock.replayAll();
}
}
(I'm aware this question is a few months old, but it might help others, though)
Try using:
#PrepareForTest({ResourceBundle.class, BeanBeingTested.class})
With only ResourceBundle in the PrepareForTest the mock will work when called directly from your unit test method, but when called from BeanBeingTested you get the real method being used.
Powermock documentation is lacking in this area.
Why bother mocking the call to the resource bundle? Generally, I try to avoid mocking the nuts and bolts of java, such as ArrayList, Date, etc. Resource bundles (and MessageFormat.format()) more or less fall into the same category for me. They generally operate on strings which are fundamentals, and if these things are broken or changing their behavior enough to break a test it's definitely something I want to know :)
Just let them grab the string (which presumably is about to be set in the UI, perhaps after . Don't bother to assert the value returned since you don't want edits to the bundle to break your test. If the string gets set on a mock UI component, This is a good place for anyObject(String.class) which correctly expresses the fact you (probably) don't actually care about the specific string displayed.
I also consider it a benefit when the test fails due to a missing message key. THAT I want to know.

How to set expectation to params passed to void methods using EasyMock

I am using EasyMock and EasyMock CE 3.0 to mock dependent layers and test my classes. Below is the scenario for which I am not able to find any solution
I have class to be tested, which calls a dependent class void method that takes an input param, and alters the same param. The method that I am testing is doing some operations based on the altered param, which I have to test now for various scenarios
Consider the below sample, where I have tried to put the same scenario
public boolean voidCalling(){
boolean status = false;
SampleMainBean mainBean = new SampleMainBean();
dependentMain.voidCalled(mainBean);
if(mainBean.getName() != null){
status = true;
}else{
status = false;
}
return status;
}
And the dependentMain class the below method
public void voidCalled(SampleMainBean mainBean){
mainBean.setName("Sathiesh");
}
To have full coverage, I need to have 2 test cases to test both the scenarios where true and false are returned, but I always get false as I am not able to set the behaviour of the void method to alter this input bean. How can I get a true as result in this scenario using EasyMock
Thanks in advance for any help.
Starting from the answer in this answer: EasyMock: Void Methods, you can use IAnswer.
// create the mock object
DependentMain dependentMain = EasyMock.createMock(DependentMain.class);
// register the expected method
dependentMain.voidCalled(mainBean);
// register the expectation settings: this will set the name
// on the SampleMainBean instance passed to voidCalled
EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
#Override
public Object answer() throws Throwable {
((SampleMainBean) EasyMock.getCurrentArguments()[0])
.setName("Sathiesh");
return null; // required to be null for a void method
}
});
// rest of test here
Thanks for your reply.. I got the problem resolved... :)
Thanks for the sample code too.
Using the above code snippet, One change that I had to do is,
// register the expected method
dependentMain.voidCalled((SampleMainBean) EasyMock.anyObject());
With this am able to get the updated bean in the method to be tested.
Thanks again for your help.

How do I mock a static method that returns void with PowerMock?

I have a few static util methods in my project, some of them just pass or throw an exception. There are a lot of examples out there on how to mock a static method that has a return type other than void. But how can I mock a static method that returns void to just "doNothing()"?
The non-void version uses these lines of code:
#PrepareForTest(StaticResource.class)
...
PowerMockito.mockStatic(StaticResource.class);
...
Mockito.when(StaticResource.getResource("string")).thenReturn("string");
However if applied to a StaticResources that returns void, the compile will complain that when(T) is not applicable for void...
Any ideas?
A workaround would probably be to just have all static methods return some Boolean for success but I dislike workarounds.
You can stub a static void method like this:
PowerMockito.doNothing().when(StaticResource.class, "getResource", anyString());
Although I'm not sure why you would bother, because when you call mockStatic(StaticResource.class) all static methods in StaticResource are by default stubbed
More useful, you can capture the value passed to StaticResource.getResource() like this:
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
PowerMockito.doNothing().when(
StaticResource.class, "getResource", captor.capture());
Then you can evaluate the String that was passed to StaticResource.getResource like this:
String resourceName = captor.getValue();
Since Mockito 3.4.0, an experimental API was introduced to mock static methods.
The following example code has been tested with Mockito 4.3.1 (testImplementation("org.mockito:mockito-inline:4.3.1), and JUnit Jupiter 5.8.2, OpenJDK 11.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.util.UUID;
public class StaticMockTest {
#Test
void showCaseStaticMock() {
try (MockedStatic<StaticMockTest> staticMock = Mockito.mockStatic(StaticMockTest.class)) {
staticMock.when(StaticMockTest::getUUIDValue).thenReturn("Mockito");
Assertions.assertEquals("Mockito", StaticMockTest.getUUIDValue());
}
// Regular UUID
UUID.fromString(StaticMockTest.getUUIDValue());
}
public static String getUUIDValue() {
return UUID.randomUUID().toString();
}
}
Previous Answer, probably Mockito 1.x/2.x with Powermock 1.x/2.x
You can do it the same way you do it with Mockito on real instances. For example you can chain stubs, the following line will make the first call do nothing, then second and future call to getResources will throw the exception :
// the stub of the static method
doNothing().doThrow(Exception.class).when(StaticResource.class);
StaticResource.getResource("string");
// the use of the mocked static code
StaticResource.getResource("string"); // do nothing
StaticResource.getResource("string"); // throw Exception
Thanks to a remark of Matt Lachman, note that if the default answer is not changed at mock creation time, the mock will do nothing by default. Hence writing the following code is equivalent to not writing it.
doNothing().doThrow(Exception.class).when(StaticResource.class);
StaticResource.getResource("string");
Though that being said, it can be interesting for colleagues that will read the test that you expect nothing for this particular code. Of course this can be adapted depending on how is perceived understandability of the test.
By the way, in my humble opinion you should avoid mocking static code if your crafting new code. At Mockito we think it's usually a hint to bad design, it might lead to poorly maintainable code. Though existing legacy code is yet another story.
Generally speaking if you need to mock private or static method, then this method does too much and should be externalized in an object that will be injected in the tested object.
Hope that helps.
Regards
In simpler terms,
Imagine if you want mock below line:
StaticClass.method();
then you write below lines of code to mock:
PowerMockito.mockStatic(StaticClass.class);
PowerMockito.doNothing().when(StaticClass.class);
StaticClass.method();
To mock a static method that return void for e.g. Fileutils.forceMKdir(File file),
Sample code:
File file =PowerMockito.mock(File.class);
PowerMockito.doNothing().when(FileUtils.class,"forceMkdir",file);

During suite tests EasyMock says 0 matchers expected 1 recorded

So I've been using EasyMock's class extension for a while now. All of a sudden I'm getting this exception, but only when I run the entire test suite:
java.lang.IllegalStateException: 0 matchers expected, 1 recorded.
at org.easymock.internal.ExpectedInvocation.createMissingMatchers(ExpectedInvocation.java:42)
at org.easymock.internal.ExpectedInvocation.<init>(ExpectedInvocation.java:34)
at org.easymock.internal.ExpectedInvocation.<init>(ExpectedInvocation.java:26)
at org.easymock.internal.RecordState.invoke(RecordState.java:64)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:24)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:56)
at org.easymock.classextension.internal.ClassProxyFactory$1.intercept(ClassProxyFactory.java:74)
at com.protrade.soccersim.data.emulator.matrix.PositionCategoryMatrix$$EnhancerByCGLIB$$c5298a7.getPossession(<generated>)
at com.protrade.soccersim.data.emulator.stats.team.PossessionCalculatorUnitTest.testDeterminePossessionHomeWin(PossessionCalculatorUnitTest.java:45)
The code involved is this little beauty (trimmed a bit):
#Before
public void setUp() throws Exception {
homeTeam = createMock( PositionCategoryMatrix.class );
awayTeam = createMock( PositionCategoryMatrix.class );
...
}
#Test
public void testDeterminePossessionHomeWin() {
expect(homeTeam.getPossession()).andReturn( 0.15151515 );
expect(awayTeam.getPossession()).andReturn( 0.01515152 );
replay( homeTeam, awayTeam );
...
}
The exception is being thrown on the first expect. And it really doesn't make sense. It says it's getting a matcher, but the method doesn't even take an argument. And odd enough it's only during test suites! I'm creating a new mock in the #Before, so it shouldn't be inheriting anything from somewhere else (not that some other method would have a matcher on it)
So, any ideas?
I was sick and tired of seeing this with each new legacy code base with EasyMock I had to work with. Write one new EasyMock test by the book and all of the sudden random tests start failing because of Matchers never captured. So I went looking how EasyMock stores those Matchers. It makes use of a final class LastControl, in that class are a few threadlocals where different things get stored. One of those was for the Matchers. Luck has it that there is a static method on there to pull all the Matchers from the threadlocal that where still on there. So this gave me this idea (with help of a collegue, thanks Sven, he wanted credit)
/**
* Base class to make sure all EasyMock matchers are cleaned up. This is not pretty but it will work
*
* #author N069261KDS
*
*/
public class BaseTest {
#Before
public void before(){
LastControl.pullMatchers();
}
#After
public void after(){
LastControl.pullMatchers();
}
}
Basicly let your test that fail with the Matchers error extend from this class and you'll be sure the Matchers are cleaned. Note this IS A WORKAROUND. The offending tests should have been written right in the first place. But if you have to wade through 5000+ tests , this is the lesser of two evils. I hope this will help people out !
While it's true that this can be a spurious message resulting from a "silly" EasyMock bug, it is also very likely to be due to invalid usage of the EasyMock API. In my case the message arose from this JUnit 3.8 test (and like you, this only happened when I ran my entire suite of tests, and only via Maven, not Eclipse):
public void testSomething() {
// Set up
MyArgumentType mockArg = (MyArgumentType) EasyMock.anyObject(); // bad API usage
// Invoke the method under test
final String result = objectUnderTest.doSomething(mockArg);
// Verify (assertions, etc.)
...
}
Instead of using anyObject(), I should have used createMock(MyArgumentType.class) or one of its variants. I don't know what I was thinking, I've written millions of these tests and used the API correctly.
The confusing bit is that the test that fails with the "wrong number of matchers" message isn't necessarily (or ever?) the one in which you used the API wrongly. It might be the first test executed after the buggy one that contains a replay() or verify() method, but I haven't verified this experimentally.
I had the same error message. I was (accidentally) using an isA() declaration in the call on the class under test
I.e.
classUnderTest.callStateChanged(calls, isA(LoggingOnlyListener.class));
when I meant:
classUnderTest.callStateChanged(calls, new LoggingOnlyListener());
And it was the test AFTER this one that failed every time.
I just ran into this problem, and I think I managed to figure it out. For me it was due the the previous test (that's in a different Class), where I was (incorrectly) using an EasyMock matcher in an Assert.assertEquals method.
It seems EasyMock couldn't complain about the extra matcher reported until the first expects methods was called.
I am running into a similar problem. From what I observed, even method returns are matched using Matchers. So if your first method fails for any reason, the matcher for the return match is still in the stack. That could be one reason why you are seeing 1 matchers recorded even when your method doesn't take any argument. Basically, the first method invocation never returned a value.
Which version of Easymock are you using?
I read a post about the release of v.2.5.2 and previuous versions might have a
dumb bug on the capture
try to use Easymock 2.5.2+

Resources