This one is probably a PowerMock/EasyMock 101 question which I cannot figure out why. I have a class C with methods
public static boolean testInner(String s) {
return false;
}
public static boolean testOuter() {
String x = "someValue";
return testInner(x);
}
In my test of testOuter() method I want to ensure testInner is called with appropriate parameter. To do so, I am doing something like this: [@RunWith(PowerMockRunner.class) @PrepareForTest(EmailUtil.class) declared at Class level]
EasyMock.expect(C.testInner("blabla")).andReturn(true);
PowerMock.replayAll();
boolean status = C.testOuter();
PowerMock.verifyAll();
assertTrue(status);
But I am getting error as:
java.lang.AssertionError:
Unexpected method call testOuter():
testInner("blabla"): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:45)
at org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl.invoke(EasyMockMethodInvocationControl.java:95)
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:105)
at org.powermock.core.MockGateway.methodCall(MockGateway.java:60)
at C.testOuter(C.java)
I replaced the actual parameter with EasyMock.IsA(String.class) but still no luck. I am pretty sure I am doing something fundamentally silly here. Any help?
easymock. EasyMock: mock(…): generates a mock of the target class, be it a concrete class or an interface. Once created, a mock is in “recording” mode, meaning that EasyMock will record any action the Mock Object takes, and replay them in the “replay” mode.
While Mockito can help with test case writing, there are certain things it cannot do viz:. mocking or testing private, final or static methods. That is where, PowerMockito comes to the rescue. PowerMockito is capable of testing private, final or static methods as it makes use of Java Reflection API.
The expect() method tells EasyMock to simulate a method with certain arguments. The andReturn() method defines the return value of this method for the specified method parameters. The times() method defines how often the Mock object will be called. The replay() method is called to make the Mock object available.
Benefits of EasyMockNo Handwriting − No need to write mock objects on your own. Refactoring Safe − Renaming interface method names or reordering parameters will not break the test code as Mocks are created at runtime. Return value support − Supports return values. Exception support − Supports exceptions.
I think there are two issues here, one has to do with a missing call in your test code. The second has to do with your understanding of behavioral mocking and the difference between full and partial mocking.
You seem to be missing a call to PowerMock.mockStatic
or one of the PowerMock.mockPartialMock
methods (see also this). The first method will mock all static methods passed to it, while the second will mock only the list of methods it's given.
Here's a complete example with two test methods that illustrate the two options. First, we have to annotate the test class using these two annotations:
@RunWith(PowerMockRunner.class)
@PrepareForTest(Dummy.class)
public class DummyTest {
The first annotation tells JUnit to run the test using PowerMockRunner. The second annotation tells PowerMock to prepare to mock the class Dummy.
Next, we'll look at the an example where all the static methods from class Dummy
are mocked. What does this mean? It means essentially that we'll like to replace the actual implementation with fake ones (mocks). How should this fake implementation behave? This is what we specify in expectation.
Thus, in the testStaticMock
method, we're telling EasyMock to give us a fake implementation of the two methods. We'll like the fake Dummy.testOuter
to simply return true
. And we'll like the fake Dummy.testInner to return true
when passed the argument "bb"
. Note that when these mocks are activated (PowerMock.replayAll
), the test code will only run the fake methods and not the actual implementation -- this appears to be the source of your confusion. I have more to say on that later.
@Test
public void testStaticMock() {
mockStatic(Dummy.class);
EasyMock.expect(Dummy.testOuter()).andReturn(true);
EasyMock.expect(Dummy.testInner("bb")).andReturn(true);
replayAll();
boolean status = Dummy.testOuter();
Assert.assertTrue(status);
status = Dummy.testInner("bb");
Assert.assertTrue(status);
verifyAll();
}
Here is another test where we don't mock all the methods, only the ones that we pass to mockStaticPartial
. Below, we are telling PowerMock that we only want to mock the method Dummy.testInner
. Thus, part of Dummy
is mocked and the rest is the class under test.
@Test
public void testPartialStaticMock() {
mockStaticPartial(Dummy.class, "testInner");
EasyMock.expect(Dummy.testInner("someValue")).andReturn(true);
replayAll();
boolean status = Dummy.testOuter();
verifyAll();
Assert.assertTrue(status);
}
}
And let the mocked class Dummy
be defined as follows:
public class Dummy {
public static boolean testInner(String s) {
return false;
}
public static boolean testOuter() {
String x = "someValue";
return testInner(x);
}
}
One thing to understand about full static mocking is that all the static methods are mocked. Thus, the method testOuter
will be replace by a mocked version will have a implementation such as the following:
public static boolean testOuter() {
return true; //or whatever value is provided in the expectation
}
Thus, we shouldn't expect the mocked version to invoke methods that the actual implementation does. We didn't want to care about the internals of the method. This was the reason, we decided to mock it anyway -- to replace its internals with a toy implementation, defined only by the expectation we set for it.
One the other hand, when we did partial mocking, we didn't mock testOuter
, so we were invoking its actual implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With