isurrender
isurrender

Reputation: 33

How to mock private method of another Class other than the Class under test using PowerMock?

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

Answers (1)

troig
troig

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

Related Questions