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

20,143

Solution 1

I don't think this is a problem with PowerMock. It looks like it should work just fine as is. I wonder if there is a problem with TestNG interacting with PowerMock?

I have no experience with TestNG, so I tried running the class in JUnit. SomeClass was left as 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 a PowerMockRunner.class using @RunWIth or some similar annotation, as with JUnit? If I remove that annotation I recieve the same error message 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 object factory. To do this programmatically, add a method like this to your test class:

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

or to be on the safe side you can also extend from the PowerMockTestCase:

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

Solution 2

You can't do by that way. Did you try to use reflection?

By using reflection, you can mock the private methods by mocking the invoke methods, or simpler: you can change it to public temporary, then after the test (maybe in the tearDown) - you can change it back to private.

Hope this help.

Share:
20,143
Thomas
Author by

Thomas

Updated on July 22, 2022

Comments

  • Thomas
    Thomas almost 2 years

    I want to write a unit test for a class I have. This class has a public method, and inside the public method there are calls to private methods in the same class. I want to mock the calls to those 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 tests 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 hints:

    FAILED: testSomePublicMethod
    org.mockito.exceptions.misusing.UnfinishedStubbingException: 
    Unfinished stubbing detected here:
    -> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:31)
    
    E.g. 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've looked at some examples online but I haven't found one that uses PowerMock with Mockito and TestNG specifically to do what I want. Can someone give me some pointers on what I could do differently?