Reputation: 629
I would like to know if there is a way to verify and call made to a mock created for a private static method called from a public static method under test.
Here is my public static method under test
public static String methodUnderTest(String p1){
return privateStaticMethod(p1);
}
private static String privateStaticMethod(String p1){
return "dummy";
}
I have mocked the private static method using powermokito as follows:
@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "ClassUnderTest")
public class ClassUnderTestTest {
@Test
public void test_sometest() throws Exception {
PowerMockito.spy(ClassUnderTest.class);
PowerMockito.doReturn("whatever").when(ClassUnderTest.class, "privateStaticMethod","something");
String retValue = ClassUnderTest.methodUnderTest("something");
assertEquals(retValue, "whatever");
}
}
Now, is there a way to verify that privateStaticMethod was called ?
Upvotes: 0
Views: 2832
Reputation: 140457
Turns out to be really complicated.
If this can be made to work, the solution goes probably along what is written up here. Unfortunately I don't have a PowerMockito setup, so I can't test this code myself:
// tell powermock(ito) that you want to do PARTIAL static mocking
PowerMockito.spy(ClassUnderTest.class);
// give it the mocking SPEC for that static method that needs mocking
PowerMockito.doReturn("whatever").when(ClassUnderTest.class, "privateStaticMethod","something");
// tell it to INVOKE the real method when the public one is called
PowerMockito.doCallRealMethod().when(Util, "methodUnderTest", any());
// now assert that the mock spec kicked in
assertThat(ClassUnderTest.methodUnderTest("something"), is("whatever"));
The above uses the Hamcrest is()
matcher, and any()
would be a (Power)Mockito argument matcher. Make sure that the imports are correct!
The above should fail when you change your public method and don't invoke that private method, and/or return something else.
But the real answer is: you should avoid such kind of tests. The above code implicitly verifies that this private method was called: if it isn't called, you should receive a different result!
But the real point here is: you shouldn't be testing such things. How your public method gets to its result shouldn't matter to to your tests at all. Your public method has a contract, and how that is implemented is an implementation detail.
Your approach turns your unit test into a (overly complex!) re-implementation of your production code. That means: the second you intend to change your implementation your test needs to be adapted. Worse, because you pass the method name as raw string, you won't even notice until runtime, when all of a sudden the method stops returning whatever
, but gives you dummy
.
So, the real answer here is:
It is pointless to verify that the private method was called. A caller of your public method should return about "what goes in, and what comes back". Anything else should not matter on that level.
And given the OP's comment:
In other words: if you can't write a simple straight forward test in Mockito, then most likely you created hard to test production code, and you it would be much better to invest time and energy to make the production code easier to test. Instead of using the PowerMock(ito) hammer to "fix" your problem by working around symptoms. And yes, this matters. We came from a PowerMock-based "too much static" code base, and simply told people at some point "no more". Since then, when we need mocking, we use Mockito. And the number of bizarre "unit test fails" due to "change to static" in a different place went down to 0. And our production code became better.
Upvotes: 1