Mocking private methods used in a public method with PowerMock, Mockito, and TestNG

I want to write unit test for the class that I have. This class has an open method, and inside the public method there are calls for private methods in the same class. I want to mock the calls of these private methods. The class is similar to this:

public class SomeClass { public int somePublicMethod(int num) { int num2 = somePrivateMethod1(num); int num3 = somePrivateMethod2(num); return num2 + num3; } private int somePrivateMethod1(int num) { return 2*num; } private int somePrivateMethod2(int num) { return 3*num; } } 

For my unit test, I am trying to use PowerMock with Mockito and TestNG. Here is my attempt at a test that checks somePublicMethod:

 import static org.powermock.api.mockito.PowerMockito.doReturn; import static org.powermock.api.mockito.PowerMockito.spy; import org.powermock.core.classloader.annotations.PrepareForTest; import org.testng.Assert; import org.testng.annotations.Test; @PrepareForTest(SomeClass.class) public class SomeClassTest { @Test public void testSomePublicMethod() throws Exception { int num = 4; SomeClass someClassSpy = spy(new SomeClass()); doReturn(8).when(someClassSpy, "somePrivateMethod1", num); doReturn(12).when(someClassSpy, "somePrivateMethod2", num); int result = someClassSpy.somePublicMethod(num); Assert.assertEquals(result, 20); } } 

When I run this test, I get an exception and some tips:

 FAILED: testSomePublicMethod org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: -> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:31) Eg thenReturn() may be missing. Examples of correct stubbing: when(mock.isOk()).thenReturn(true); when(mock.isOk()).thenThrow(exception); doThrow(exception).when(mock).someVoidMethod(); Hints: 1. missing thenReturn() 2. you are trying to stub a final method, you naughty developer! 

I looked at a few examples on the Internet, but I did not find one that uses PowerMock with Mockito and TestNG specifically to do what I want. Can someone give me some guidance on what I could do differently?

+4
source share
3 answers

I do not think this is a problem with PowerMock. It looks like it should work fine as it is. I wonder if there is a problem with TestNG interacting with PowerMock?

I have no experience with TestNG, so I tried to run the class in JUnit. SomeClass remained as it is, SomeClassTest was minimally modified to use JUnit:

 import static org.powermock.api.mockito.PowerMockito.*; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest(SomeClass.class) public class SomeClassTest { @Test public void testSomePublicMethod() throws Exception { final int num = 4; final SomeClass someClassSpy = spy(new SomeClass()); doReturn(8).when(someClassSpy, "somePrivateMethod1", num); doReturn(12).when(someClassSpy, "somePrivateMethod2", num); final int result = someClassSpy.somePublicMethod(num); Assert.assertEquals(result, 20); } } 

The test passes.

Do you need to specify PowerMockRunner.class with @RunWIth or some similar annotation like with JUnit? If I delete this annotation, I get the same error message that you posted.

EDIT:

According to this link: http://code.google.com/p/powermock/wiki/TestNG_usage

You need to tell TestNG to use the PowerMock factory object. To do this programmatically, add the following method to the test class:

 @ObjectFactory public IObjectFactory getObjectFactory() { return new org.powermock.modules.testng.PowerMockObjectFactory(); } 

or to be safe, you can also go from PowerMockTestCase:

 @PrepareForTest(SomeClass.class) public class SomeClassTest extends PowerMockTestCase { //... } 
+5
source

You cannot do this. Have you tried to use reflection?

Using reflection, you can scoff at private methods, making fun of calling methods or easier: you can change it to public, and then after the test (possibly in tearDown) - you can change it to private.

I hope for this help.

+1
source

I think you click the Mockito limit here. In such cases, I use the Powermock method replacement or declare the target method as protected and override it when building the test instance of the class. Hope this helps.

0
source

Source: https://habr.com/ru/post/1411646/


All Articles