Reputation: 33
I have a class which I would like to test with a public method that calls the private method of another class. When I try calling the private method of the same class, everything works perfectly. The problem occours when I try to mock another private method that gets called from the class under test. Following is the code sample of the test class.
@RunWith(PowerMockRunner.class)
@PrepareForTest({CodeWithPrivateMethod.class,CodeWithAnotherPrivateMethod.class})
public class CodeWithPrivateMethodTest {
@Test
public void when_gambling_is_true_then_always_explode() throws Exception {
CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());
CodeWithAnotherPrivateMethod codeWithAnotherPrivateMethod = PowerMockito.spy(new CodeWithAnotherPrivateMethod());
/*when(codeWithAnotherPrivateMethod, method(CodeWithAnotherPrivateMethod.class, "doTheGame", String.class))
.withArguments(anyString())
.thenReturn(true);*/
PowerMockito.when(codeWithAnotherPrivateMethod, "doTheGame", anyString()).thenReturn(true);
//PowerMockito.doReturn(true).when(codeWithAnotherPrivateMethod, "doTheGamble", anyString(),anyInt());
spy.meaningfulPublicApi();
}
}
Following is the code sample for the class under test
import java.util.Random;
public class CodeWithPrivateMethod {
CodeWithAnotherPrivateMethod anotherPrivateMethod = new CodeWithAnotherPrivateMethod();
public void meaningfulPublicApi() {
if (anotherPrivateMethod.doTheGame("Whatever")) {
System.out.println("kaboom");
}
}
}
And Following is the code sample for the class that gets called from the class under test
import java.util.Random;
public class CodeWithAnotherPrivateMethod {
public boolean doTheGame(String string) {
return doTheGamble("Whatever", 1 << 3);
}
private boolean doTheGamble(String whatever, int binary) {
Random random = new Random(System.nanoTime());
boolean gamble = random.nextBoolean();
return gamble;
}
}
So My Question is how do i succesfully mock doTheGamble() method of CodeWithAnotherPrivateMethod Class to make it return true always?
Upvotes: 2
Views: 1628
Reputation: 7212
The problem here is although you are creating a spy of CodeWithAnotherPrivateMethod
in your test, a new instance of CodeWithAnotherPrivateMethod
is created in CodeWithPrivateMethod
. So, actually you are not using your mock.
CodeWithAnotherPrivateMethod anotherPrivateMethod = new CodeWithAnotherPrivateMethod();
To avoid this, you can force to return your CodeWithAnotherPrivateMethod mock when a new instance is created. You can use PowerMockito whenNew()
capability to do this.
Example:
PowerMockito.whenNew(CodeWithAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithAnotherPrivateMethod);
Finally, your test should be something like this:
@Test
public void when_gambling_is_true_then_always_explode() throws Exception {
// Spy CodeWithAnotherPrivateMethod and force return true when doTheGamble is called
CodeWithAnotherPrivateMethod codeWithAnotherPrivateMethod = PowerMockito.spy(new CodeWithAnotherPrivateMethod());
PowerMockito.doReturn(true).when(codeWithAnotherPrivateMethod, "doTheGamble", Mockito.anyString(), Mockito.anyInt());
// Return your mock when a new instance of CodeWithAnotherPrivateMethod is created.
PowerMockito.whenNew(CodeWithAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithAnotherPrivateMethod);
CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());
spy.meaningfulPublicApi();
}
Hope it helps.
Upvotes: 2