Unit testing with PowerMock
Java, Test ·In this article I will implement unit testing with PowerMock library. This framework is more powerful than other libraries and allows you to mock static methods, private methods and change field properties among other things. I will use the Mockito extension but it also supports EasyMock.
1 Installation
If you use Maven, you can add the following dependencies to your pom.xml:
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>1.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.5</version> <scope>test</scope> </dependency>
Otherwise, you can get the libraries from the powermock github repository.
2 Preparing the tests
You must add the @RunWith annotation. This annotation will tell JUnit to use the class PowerMockRunner to run the tests.
@RunWith(PowerMockRunner.class) public class FooTester { private Foo foo; @Before public void prepareTest() { foo = PowerMockito.spy(new Foo()); }
I’m going to test Foo.class. Using the spy method, all real methods of the class will be invoked except those I mock.
3 Mocking private methods
I want to test methodWithPrivateDependency, but this method internally calls a private method which, let’s say, calls an external resource.
public String methodWithPrivateDependency() { myPrivateMethod(); return resolveApplicationId(); } private String resolveApplicationId() { return "testApplication"; } private void myPrivateMethod() { throw new RuntimeException("tsk, tsk you invoked private method!"); }
The test:
@Test @PrepareForTest(Foo.class) public void checkApplicationIdIsResolved() throws Exception { PowerMockito.doNothing().when(foo, "myPrivateMethod"); Assert.assertEquals("testApplication", foo.methodWithPrivateDependency()); PowerMockito.verifyPrivate(foo).invoke("myPrivateMethod"); }
The @PrepareForTest annotation tells PowerMock to prepare the class so it can manipulate it. This is necessary if the class is final, or it contains final, private, static or native methods that should be mocked. In this case, I will need to mock the private method.
If you put this annotation at class level, it will affect all test methods within the class. It would be as follows:
@PrepareForTest({Class1.class, ..., ClassN.class})
4 Mocking static access
The next method that needs to be tested gets some information by accessing a static method of an inner static class. Seems like we need to mock the static access.
The method to test:
public String getCriticalMessage() { String name = Bar.Baz.getData(); return "hello " + name; }
The static class:
public class Bar { public static class Baz { public static String getData() { throw new RuntimeException("tsk, tsk you invoked getData!"); } } }
The test:
@Test @PrepareForTest(Bar.Baz.class) public void testStaticDependency() { PowerMockito.mockStatic(Bar.Baz.class); PowerMockito.when(Bar.Baz.getData()).thenReturn("world!"); Assert.assertEquals("hello world!", foo.getCriticalMessage()); }
I use the @PrepareForTest annotation because I need to mock the static method getData of this class.
5 Mocking chained dependencies
In this example, I want to mock the chainMocks method. There’s a singleton Helper class which returns a manager from which the method to test invokes it.
public String chainMocks(){ Helper.getInstance().getConfigurationManager().initializeRegistry(); return "chained"; }
The test:
@Test @PrepareForTest(Helper.class) public void testChainedDependencies() { Helper helperMock = PowerMockito.mock(Helper.class); PowerMockito.mockStatic(Helper.class); PowerMockito.when(Helper.getInstance()).thenReturn(helperMock); ConfigurationManager mockManager = PowerMockito.mock(ConfigurationManager.class); PowerMockito.when(helperMock.getConfigurationManager()).thenReturn(mockManager); Assert.assertEquals("chained", foo.chainMocks()); }
I only need to prepare Helper class for test because I need to mock its static method getInstance. That’s not the case for ConfigurationManager where initializeRegistry is a public instance method.