Praveen Kamath
Praveen Kamath

Reputation: 1059

PowerMockito mock private methods in springboot

I am trying to mock a private method inside my class under test which is as below.

public String processPayment(...) {
    //some lines
    privateMethod(...);
    return "";
}

private Object privateMethod(...) {
    //some lines
    return someObject;
}

Now I need to test processPayment method and mock privateMethod.

I tried creating spy of the above class, but the method gets called when I do below

final DeviceCheckoutServiceImpl spyDeviceCheckoutService = spy(injectedMockBeanOfAboveClass); //@InjectMock in test class
PowerMockito.doReturn(null).when(spyDeviceCheckoutService, "privateMethod", ArgumentMatchers.anyMap()); //method gets called here
spyDeviceCheckoutService.processPayment(...); //private method isn't mocked somehow, and gets called here too

The privateMethod gets called on the 2nd line itself. Also, the privateMethod isn't mocked.

Maybe I am creating the spy object in a wrong way? Can't do spy(new DeviceCheckoutServiceImpl()); as it needs bean instantiation.

Powermockito version:

compile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.0'
compile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.0'

Let me know what I am doing wrong here.

Upvotes: 5

Views: 7625

Answers (3)

Praveen Kamath
Praveen Kamath

Reputation: 1059

Issue solved! Had forgot to add @PrepareForTest(DeviceCheckoutServiceImpl.class) on the test class.

Upvotes: 4

Strelok
Strelok

Reputation: 51451

Mockito introduced AdditionalAnswers.delegatesTo to support spying on Spring proxies and other such things:

Check out this issue: https://github.com/mockito/mockito/issues/529#issuecomment-239494581

So instead of spy(proxy) use mock(TestSubject.class, delegatesTo(springProxy)).

However if annotations are need to read, then you'll need mockito 2 beta. Because mockito 1.x uses CGLIB which doesn't copies annotations on the mockito subclass. Mockito 2 uses the great bytebuddy.

Upvotes: 0

Mebin Joe
Mebin Joe

Reputation: 2209

In the test class we will call the spy() method of org.powermock.api.mockito.PowerMockito by passing the reference to the class that needs to be tested:

MockPrivateMethodExample spy = PowerMockito.spy(mockPrivateMethodExample);

Then we define what we want to do when this particular private method is called.

PowerMockito.doReturn("Test").when(spy, {$methodName});

MockPrivateMethodExample.java

public class MockPrivateMethodExample {

  public String getDetails() {
    return "Mock private method example: " + iAmPrivate();
  }

  private String iAmPrivate() {
    return new Date().toString();
  }
}

MockPrivateMethodTest.java

@RunWith(PowerMockRunner.class)
@PrepareForTest(MockPrivateMethodExample.class)
public class MockPrivateMethodTest {

  private MockPrivateMethodExample mockPrivateMethodExample;

  // This is the name of the private method which we want to mock
  private static final String METHOD = "iAmPrivate";

  @Test
  public void testPrivateMethod() throws Exception {
    mockPrivateMethodExample = new MockPrivateMethodExample();

    MockPrivateMethodExample spy = PowerMockito.spy(mockPrivateMethodExample);
    PowerMockito.doReturn("Test").when(spy, METHOD);
    String value = spy.getDetails();

    Assert.assertEquals(value, "Mock private method example: Test");
    PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke(METHOD);
  }
}

More details here: https://examples.javacodegeeks.com/core-java/mockito/mockito-mock-private-method-example-with-powermock/

Upvotes: 8

Related Questions