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

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:

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:

To achieve this we can do:

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

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:

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:

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:

You can also stub methods:

And replace method invocations:

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.

22 Comments

  1. Seems really cool! I’m gonna give it a try right now :).

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

  3. 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).

  4. 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)

  5. 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) ?

  6. Johan Haleby

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

  7. 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

  8. 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

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

  10. 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?

  11. 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.

  12. Hi,

    This is probably because you’re using a version of PowerMock that is not compatible with Mocktio 1.8.3. See the documentation at (http://code.google.com/p/powermock/wiki/MockitoUsage13) for which version to use.

    /Johan

  13. 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.

  14. Excellent Post!
    Taking inspiration from you, I have also written a post on how to test the untestable code (with an example taken from JMockit samples). I am showing various ways in which we can write good unit-tests for the code under test using the PowerMocks (Mockito api).

    Here is the link:
    http://www.gitshah.com/2010/05/testing-untestable-code-using.html

  15. Balrajcse

    I have method call like

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

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

  16. AllanC

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

  17. enric

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

  18. 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

  19. 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.

  20. 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

  21. 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;
    }

Trackbacks for this post

  1. Fixing Common PowerMock Problems » Angus Macdonald

Leave a Reply