Pages

Saturday, November 30, 2013

How to use PowerMock and Mockito to test static and private methods

Introduction

This article is not another diatribe to tell you the importance of unit testing. I think we can all agree that it is important. This is about solving an issue that comes up frequently in unit testing. How do I test static methods, and how do you test private methods.

Until PowerMock, most developers were told you can't really test a static method per se. I will show how to do it below.

A common mechanism for testing private methods is to change them to protected. This is not a good solution for a number of reasons. So how do we test them? Again, PowerMock has come to the rescue.
I want solutions. I use Arquillian, but I am not such a zealot that I will chant the mantra that mocking is evil and should not be done. It is a means to an end. That being said, we use Mockito which in my professional experience is the best current mocking framework available. It is easy to setup and use.
However, Mockito has its limitations. Two are mentioned above. The fine developers of PowerMock have come up with an additional framework to use in conjunction with Mockito to get around the limitations.

Solution

The Apache Maven sample code for the project was developed using NetBeans and can be found on Bitbucket here: unit-testing-mockito-powermockito.

Since I am a Apache Maven user, I simply add the relevant frameworks to my pom.xml as shown below: Once the test frameworks are in place, I can use the PowerMockRunner to help me with my testing. The following are some simple classes to demonstrate how to test. The first is a class to generate UUID values for IDs.

IdentityUtilities.java


Next, I need a class to represent a person. I am interested in testing the private method generateId.

Person.java


Finally, we need our PersonTest class to test our Person object. The explanation follows the code.

PersonTest.java


The @RunWith(PowerMockRunner.class) annotation tells jUnit that we are using an extension to handle testing of this class. This tells jUnit to use this test runner instead of its own test runner.
The @PrepareForTest({IdentityUtilities.class, Person.class}) serves multiple purposes here. The first is to tell PowerMock that we need to do some preparation of the classes to instrument them for our testing. Classes defined using this annotation are typically those that needs to be byte-code manipulated. This includes final classes, classes with final, private, static or native methods that should be mocked and also classes that should be return a mock object upon instantiation. IdentityUtilities.class is our class with a static method, and Person.class contains our private method.

The first test testInitialize() behaves like any other Mockito test with the exception that we mock it using PowerMockito.mockStatic(IdentityUtilities.class) to initialize it. This makes testing static methods as easy as any other Mockito test.

The second test requires a little more explanation. In this case, we spy on the object we are creating. This allows us to instrument it. Then using the "spied" instance we use PowerMockito.when(instance, "generateId").thenReturn("UNIT-1A") to tell the framework that when the private method "generateId" is called, we want to return a specific value. Then we initialize the instance, and check the value is what we expected. Finally, we can optionally check to make sure that the method was actually called by using verifyPrivate(instance).invoke("generateId").

Conclusion

Don't short change yourself, and don't modify your beautifully architected code just to satisfy a testing framework. Find a framework like PowerMock to help you test your code as written instead. You should only change the code because you want to do so, or because you discover flaws in it.

No comments:

Post a Comment