Untestable code with Mockito and PowerMock

With the new release of PowerMock 1.3 we’ve focused a lot on getting the Mockito support up to par with the EasyMock support allowing mocking of e.g. final classes, static methods and new object construction using a Mockito-like syntax. Below you’ll find some examples of how to use the Mockito extension API, aka PowerMockito. Hopefully those of you used to Mockito will find PowerMock(ito) simple to use as well.

As always you need to add @RunWith(PowerMockRunner.class) at the class-level of your test in order to bootstrap PowerMock itself. The classes that are normally not mockable needs to be prepared for testability by using the @PrepareForTest annotation.

Example #1 – Static methods

public void methodToTest() {
   ..
   final long id = IdGenerator.generateNewId();
   ..
}

Let’s say that in our test we want to mock the static call to the IdGenerator.generateNewId() and have it return 2 using the Mockito extension API. This can be achieved the following way:

@RunWith(PowerMockRunner.class)
// We prepare the IdGenerator for test because the static method is normally not mockable
@PrepareForTest(IdGenerator.class)
public class MyTestClass {
    @Test
    public void demoStaticMethodMocking() throws Exception {
	mockStatic(IdGenerator.class);
       /*
        * Setup the expectation using the standard Mockito syntax,
        * generateNewId() will now return 2 everytime it's invoked
        * in this test.
        */
	when(IdGenerator.generateNewId()).thenReturn(2L);

	new ClassUnderTest().methodToTest();

	// Optionally verify that the static method was actually called
	verifyStatic();
	IdGenerator.generateNewId();
    }
}

Example #2 – Mock private methods (partial mocking)

Partial mocking of both static and instance methods works in PowerMock regardless if the method or class is final or private. Let’s say we’d like to test the “methodToTest” in isolation from the private “methodToMock” method in the example below:

public final class PrivatePartialMockingExample {
    public String methodToTest() {
        return methodToMock("input");
    }

    private String methodToMock(String input) {
        return "REAL VALUE = " + input;
    }
}

To achieve this we can do:

@RunWith(PowerMockRunner.class)
@PrepareForTest(PrivatePartialMockingExample.class)
public class PrivatePartialMockingExampleTest {
    @Test
    public void demoPrivateMethodMocking() throws Exception {
	final String expected = "TEST VALUE";
	final String nameOfMethodToMock = "methodToMock";
	final String input = "input";

	PrivatePartialMockingExample underTest = spy(new PrivatePartialMockingExample());

	/*
	 * Setup the expectation to the private method using the method name
	 */
	when(underTest, nameOfMethodToMock, input).thenReturn(expected);

	assertEquals(expected, underTest.methodToTest());

	// Optionally verify that the private method was actually called
	verifyPrivate(underTest).invoke(nameOfMethodToMock, input);
    }
}

It’s also possible to do the same thing without having to specify the method name using an overridden version of when:

@RunWith(PowerMockRunner.class)
@PrepareForTest(PrivatePartialMockingExample.class)
public class PrivatePartialMockingExampleTest {
    @Test
    public void demoPrivateMethodMocking() throws Exception {
        final String expected = "TEST VALUE";
        final String input = "input";

        /*
         * We get the method to mock by specifying the class where the
         * method is defined as well as its parameter types.
         */
        final Method methodToMock = method(PrivatePartialMockingExample.class, String.class);

        PrivatePartialMockingExample underTest = spy(new PrivatePartialMockingExample());

	// Notice how we pass the actual method instead of the name
        when(underTest, methodToMock).withArguments(input).thenReturn(expected);

        assertEquals(expected, underTest.methodToTest());

	// Optionally verify that the private method was actually called
        verifyPrivate(underTest).invoke(methodToMock).withArguments(input);
    }
}

This approach allows for more a refactor friendly code since you can change the method name of the private method without having to change your test.

Example #3 – Mock construction of new objects

Sometimes it might be good to mock construction of new objects. Consider the following example:

public class DirectoryStructure {
	public boolean create(String directoryPath) {
		File directory = new File(directoryPath);

		if (directory.exists()) {
			throw new IllegalArgumentException(""" + directoryPath + "" already exists.");
		}

		return directory.mkdirs();
	}
}

To test the create method in isolation from the file system we’d like to mock the construction of the new File instance in order to specify our expectations. To do this in PowerMock you need to prepare the class that creates the new object (since we don’t want the new object to be created in our test, we’d like to return a mock object instead). Thus we prepare DirectoryStructure.class instead of File.class. The test may look like this when we expect that the directory doesn’t exists:

@RunWith(PowerMockRunner.class)
@PrepareForTest(DirectoryStructure.class)
public class DirectoryStructureTest {
    @Test
    public void createDirectoryStructureWhenPathDoesntExist() throws Exception {
        final String directoryPath = "mocked path";

        File directoryMock = mock(File.class);

	// This is how you tell PowerMockito to mock construction of a new File.
        whenNew(File.class).withArguments(directoryPath).thenReturn(directoryMock);

	// Standard expectations
        when(directoryMock.exists()).thenReturn(false);
        when(directoryMock.mkdirs()).thenReturn(true);

        assertTrue(new NewFileExample().createDirectoryStructure(directoryPath));

        // Optionally verify that a new File was "created".
        verifyNew(File.class).withArguments(directoryPath);
    }
}

Example #4 – Modify code structure or change invocations

A new noteworthy feature of the 1.3 release is the new “member modification” API. Using this API you can suppress methods, fields or constructors as well stubbing and replacing methods and fields.
Below you can see some examples of how to suppress members in a class:

// Suppress a constructor in class ClassWithConstructor
suppress(constructor(ClassWithConstructor.class));
// Suppress method "myMethod" in class MyClass
suppress(method(MyClass.class, "myMethod"));
// Suppress all methods in class MyClass
suppress(methodsDeclaredIn(MyClass.class));
// Suppress field with name "myField" in class MyClass
suppress(field(MyClass.class, "myField"));

You can also stub methods:

//Stub the "getObject" method in class SuppressMethod to always return expectedValue
stub(method(SuppressMethod.class, "getObject")).andReturn(expectedValue);

And replace method invocations:

// Duck-typing of static methods
replace(method(MyClass.class, "getData")).with(method(MyClass2.class, "getTestData"));
// Replace method invocation with an invocation handler to allow for proxy-based AOP
replace(method(MyClass.class, "getData")).with(new MyInvocationHandler());

All methods can be statically imported from org.powermock.api.support.membermodification.MemberModifier and org.powermock.api.support.membermodification.MemberMatcher. For real examples refer to MemberModificationExampleTest.java in subversion.

Note that this also works for the EasyMock extension API.

Round up

We’ve just seen some examples of how to use PowerMock’s extension API for Mockito to allow to mock things normally not possible. For more information please visit our web page at www.powermock.org.

This Post Has 22 Comments

  1. oops! did not notice before that only JUnit was supported. Any TestNG support on its way?

  2. Johan Haleby

    Thanks!

    We’ve been working together with a member of the TestNG team in order to get it working but unfortunately there’s a bug in the latest version of TestNG which prevents this from happening. The next version of TestNG will hopefully work with PowerMock (at least basic support, which will be good enough for regular use).

  3. I’ve started to use PowerMock with some JUnit tests and that’s really amazing to be able to mock final classes (for instance, some singletons with no public constructor) that comes from some old lib you have to use because they are provided by your company and you don’t have the choice.

    So, again, Thanks a lot! (and thanks for the upcoming TestNG support :D)

  4. Johan Martinsson

    Great functionality!

    But trying out the first example I couldn’t get it to work. Shouldn’t it be
    mockStatic(IdGenerator.class ) instead of
    mock(IdGenerator.class) ?

  5. Johan Haleby

    Yes it should, I’ve corrected it now. Thanks for spotting it.

  6. Setya

    Hi,

    I have inherited method that calls ‘super()’ followed by my own implementation. I want to test this method by calling my own implementation without ‘super()’ call. Is it possible to do this with Mockito & PowerMock ?

    Regards,

    Setya

  7. Johan Haleby

    It’s currently not possible to mock super calls. You could try to suppress the method in your super class but I’m not 100% sure if that works either.

    /Johan

  8. Johan Haleby

    PowerMock 1.3.5 is now released and it has support for TestNG 5.11

  9. srikanth

    The following doesn’t seem to work
    PowerMockito.mockStatic(Integer.class);
    when(Integer.parseInt(anyString())).thenReturn(1);
    System.out.println(Integer.parseInt(“12”));

    i am getting ‘unfinished stubbing detected’ exception.
    changed the string part to this

    when(Integer.parseInt(eq(“12”))).thenReturn(1);

    but getting the same exception

    But the following works
    when(Integer.toString(anyInt())).thenReturn(“hello”);
    Integer.toString(12);
    Is this a bug or Am i missing something?

  10. Ankush Goyal

    I am using PowerMockito(1.3.6) with Mockito(1.8.3) and Junit(4.7) for testing. I am quite stuck on an error:

    [junit] Testcase: testNextPNRFromQueueHappyPath(com.orbitz.galileo.host.robot.GalpoQueueConnectionTest): Caused an ERROR
    [junit] org/mockito/internal/IMockHandler
    [junit] java.lang.NoClassDefFoundError: org/mockito/internal/IMockHandler
    [junit] at org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup.createNewSubsituteMock(DefaultConstructorExpectationSetup.java:80)
    [junit] at org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup.withArguments(DefaultConstructorExpectationSetup.java:48)
    [junit] at com.orbitz.galileo.host.robot.GalpoQueueConnectionTest.testNextPNRFromQueueHappyPath(GalpoQueueConnectionTest.java:62)
    [junit] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [junit] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    [junit] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

    My class under test : GalpoQueueConnection is basically creating a new object of another class : QueueReadBuilder. I am trying to do something like:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({GalpoQueueConnection.class, ApolloProcUtils.class})
    public class GalpoQueueConnectionTest extends TestCase{
    @Test
    public void testNextPNRFromQueueHappyPath() throws Exception {
    QueueReadBuilder mockBuilder = mock(QueueReadBuilder.class);
    PowerMockito.whenNew(QueueReadBuilder.class).withArguments(anyString(), anyString(), anyString()).thenReturn(mockBuilder);
    }
    }

    It seems like somehow powermockito is trying to call IMockHandler, and I looked at Mockito 1.8.3 api, and there isn’t any.

    Any suggestions/ clues would be welcome.

  11. Ankush Goyal

    Hi Johan,

    I am using ant/ savant for dependencies and this is what I have in my project’s build-deps file :

    Basically I am using the powermock-mockito-junit-1.3.6.zip and I don’t have any other version of mockito.

  12. Balrajcse

    I have method call like

    public void processRetrievedData() {
    super.processRetrievedData();
    }

    is there anyway to mock “super.processRetrievedData()” this.

  13. AllanC

    Very nice. I am moving our team onto our first mocking tool and it will be Mockito + Powermock. Nice job.

  14. enric

    replace() worked for me by creating the mock with PowerMockito.spy(class). I think this isn’t said in this post

  15. ra

    I have a test case where I would like to mock out multiple thrid party final classes in the same test case. Is there any way this can be done?

    The @PrepareForTest annotation can only be included once with one entry.

    Thanks

  16. Adeel Khokhar

    Hello sir…

    All the examples are so useful ,I was in process to learn about PowerMocking and after going through these examples I have got a good idea about.Well done.

    I hope you’ll keep updating us with new examples in future.

  17. Scott Shi

    Great post. It’s very helpful. I am now using PowerMock with Mockito in my testing.

    It seems that PowerMockRunner does not like Cipher.init().
    I have a method as following;

    public static void init() {
    try {
    Cipher cipher = Cipher.getInstance(“AES/CBC/PKCS5Padding”);
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(RawKeyByteArray, “AES”), new IvParameterSpec(IvParamSpecByteArray));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    Error raises when the method is called;
    java.lang.ClassCastException: com.sun.crypto.provider.AESCipher cannot be cast to javax.crypto.CipherSpi
    at javax.crypto.Cipher.a(DashoA13*..)
    at javax.crypto.Cipher.init(DashoA13*..)
    at javax.crypto.Cipher.init(DashoA13*..)
    more…

    How do you think I can get rid of the error?

    Thanks,

    Scott

  18. ravi

    how to suppress userComment

    UserComment userCommentOld = new UserComment();
    UserComment userComment=null;

    when(hibernateTemplate.getSessionFactory()).thenReturn(sessionFactory);
    when(sessionFactory.getCurrentSession()).thenReturn(session);
    when(session.createCriteria(UserComment.class)).thenReturn(criteria);

    when(criteria.add(Example.create(userCommentOld))).thenReturn(criteria);
    when(criteria.uniqueResult()).thenReturn(userComment);

    userCommentOld.setObjectForeignKey(5656L);
    userCommentOld.setObject(“sds”);

    // suppress(field(UserCommentServiceDaoImpl.class,”UserComment”));

    // suppress(method(TestaddUserCommentDao()));
    userCommentServiceDao.addUserCommentDao(5656L, “sds”, “dfdfd”, “fdfd”, “rtrtr”);
    x=1;
    assertEquals(1, x);

    in the above getting null in
    (criteria.add(Example.create(userCommentOld)))

    please help me to suppress userComment or any alternative way is there to suppress userComment

    this is code m testing

    public boolean addUserCommentDao(long objectForeignKey, String object,
    String text, String visibility, String lastUpdateUser) {
    try{
    UserComment userCommentOld = new UserComment();
    userCommentOld.setObjectForeignKey(objectForeignKey);
    userCommentOld.setObject(object);
    UserComment userComment = (UserComment)hibernateTemplate.getSessionFactory().getCurrentSession().createCriteria(UserComment.class).add(Example.create(userCommentOld)).uniqueResult();

    if(userComment==null){
    userComment=new UserComment();
    userComment.setText(text);
    userComment.setObjectForeignKey(objectForeignKey);
    userComment.setObject(object);
    userComment.setVisibility(visibility);
    userComment.setLastUpdateUser(lastUpdateUser);
    userComment.setCreateDts(new Date());
    userComment.setLastUpdateDts(new Date());
    hibernateTemplate.save(userComment);
    }
    else{
    if(text!=null && !text.isEmpty()){
    userComment.setText(text);
    userComment.setLastUpdateUser(lastUpdateUser);
    userComment.setLastUpdateDts(new Date());
    hibernateTemplate.update(userComment);
    }
    else hibernateTemplate.delete(userComment);
    }

    }
    catch(Exception e){
    return false;
    }
    return true;
    }

Leave a Reply