PowerMock is an open-source mocking library for Java applications. It extends the existing mocking frameworks, such as EasyMock and Mockito, to add even more powerful features to them. PowerMock enables us to write good unit tests for even the most untestable code. For example, most of the mocking frameworks in Java cannot mock static methods or final classes. But using PowerMock, we can mock almost any class.
PowerMock currently extends the EasyMock and Mockito mocking frameworks. Depending on which extension is preferred, the syntax to write any unit test differs slightly. In this tutorial, we are using PowerMock with Mockito.
This powermock tutorial will demonstrate a very simple mocking example using basic syntax for creating a mock and verifying a method invocation.
The primary usage of PowerMock has been the ability to mock static, final and/or private methods. Mockito2 now supports the mocking of final classes/methods. If you use Mockito2, it is recommended to use Mockito for mocking final methods/classes.
1. PowerMock Dependencies
To include powermock in our application, add the powermock-api-mockito2 and powermock-module-junit4 dependencies. Note that there is no official extension for JUnit 5.
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
If you plan to use its reflection module, for example invoking the private methods, then we need to import powermock-reflect module as well.
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
It is important to include the compatible versions of Mockito and PowerMock to avoid any possible runtime issues.
2. System Under Test
We are creating a simple class that has one private method, one final method and one static method. To eliminate unnecessary complexity, we are simply returning a String value from these methods. We will be mocking and testing these methods.
public class Service {
private String privateMessage() {
return "Hello World!";
}
public static String staticMessage() {
return "Hello World!";
}
public final String finalMessage() {
return "Hello World!";
}
}
3. Preparing PowerMockito Extension
PowerMockito is a PowerMock’s extension API to support Mockito. PowerMockito uses Java Reflection API mock final, static or private methods to help Mockito to run tests using these methods.
To prepare for tests, we apply two annotations at the test class level. Here Service class contains the methods to be mocked.
@RunWith(PowerMockRunner.class)
@PrepareForTest( { Service.class })
public class AppTest {
...
}
In @PrepareForTest annotation, we can pass the fully qualified names of types we want to mock. For example, in the given declaration, PowerMockito will prepare all classes within the specified package for mocking.
@PrepareForTest(fullyQualifiedNames = "com.howtodoinjava.demo.service.*")
4. Mocking a Static Method
For mocking static methods, PowerMock provides two approaches:
- Use
PowerMockito.mockStatic()
to a mock a static class or all the static methods in a class. - Use
PowerMockito.spy()
to mock a specific static method.
PowerMockito.mockStatic(Static.class);
Mockito.when(Static.staticMethod(paramIfAny)).thenReturn(value);
//or
Static spy = PowerMockito.spy(new Static());
PowerMockito.when(spy.staticMethod(paramIfAny)).thenReturn(value);
For the demo, we will mock the Service.staticMessage()
method which is a static method in the Service class.
@Test
public void mockStaticMethodTest() {
//Mock static methods
PowerMockito.mockStatic(Service.class);
//Set expectation
Mockito.when(Service.staticMessage()).thenReturn("New Message from Mock!");
//invoke the method
String message = Service.staticMessage();
//Assert the stub response
Assert.assertEquals(message, "New Message from Mock!");
}
To verify the static method invocation, first, call PowerMockito.verifyStatic(Static.class)
to start verifying behavior and then call the actual static method to verify. This is important to note that we need to call verifyStatic()
per static method verification.
PowerMockito.verifyStatic(Service.class);
Service.staticMessage();
To verify the number of times the method is invoked, we can pass the Mockito.VerificationMode to the verifyStatic() method.
PowerMockito.verifyStatic(Service.class, Mockito.times(1));
Service.staticMessage();
5. Mocking a Final Method
The mocking of final methods is similar to static methods, except we need to use PowerMockito.mock(class) in place of mockStatic() method.
@Test
public void mockFinalMethodTest() {
//Mock final method
Service serviceMock = PowerMockito.mock(Service.class);
//Set expectation
Mockito.when(serviceMock.finalMessage()).thenReturn("New Message from Mock!");
//invoke the method
String message = serviceMock.finalMessage();
//Assert the stub response
Assert.assertEquals(message, "New Message from Mock!");
}
To verify the final method invocations, we can use Mockito.verify() method.
//Verify final method invocation
Mockito.verify(serviceMock).finalMessage();
6. Mock a Private Method
For mocking the private methods, we will use the partial mocking using the spy() method. Also, we are using WhiteBox API to execute a private method in the class.
@Test
public void mockPrivateMethodTest() throws Exception {
Service mock = PowerMockito.spy(new Service());
PowerMockito.doReturn("New Message from Mock!").when(mock,"privateMessage");
String privateMessage = Whitebox.invokeMethod(mock, "privateMessage");
Assert.assertEquals(privateMessage, "New Message from Mock!");
}
Use PowerMockito.verifyPrivate() method to verify the private method invocations.
PowerMockito.verifyPrivate(mock, times(1)).invoke("privateMessage");
7. Enable Verbose Logging
These mock settings are rarely used but can be useful in some cases. Use them if you want to name the mocks for future debugging purposes, or if you want to enable verbose logging for extra information.
@Test
public void mockFinalMethodTest() {
//Mock final method
Service serviceMock = PowerMockito.mock(Service.class, Mockito
.withSettings()
.name("ServiceMock")
.verboseLogging());
//Set expectation
Mockito.when(serviceMock.finalMessage()).thenReturn("New Message from Mock!");
//invoke the method
String message = serviceMock.finalMessage();
//Assert the stub response
Assert.assertEquals(message, "New Message from Mock!");
//Verify final method invocation
Mockito.verify(serviceMock).finalMessage();
}
Run the above test to get the below result in the console. The finalMessage() has been referred in 3 places in the test:
- While setting the expectation, it returns null.
- When invoked on mock, it returns the stubbed response.
- While verifying it returns null.
############ Logging method invocation #1 on mock/spy ########
ServiceMock.finalMessage();
invoked: -> at com.howtodoinjava.demo.powermock.PowerMockTests.mockFinalMethodTest(PowerMockTests.java:46)
has returned: "null"
############ Logging method invocation #2 on mock/spy ########
stubbed: -> at com.howtodoinjava.demo.powermock.PowerMockTests.mockFinalMethodTest(PowerMockTests.java:46)
ServiceMock.finalMessage();
invoked: -> at com.howtodoinjava.demo.powermock.PowerMockTests.mockFinalMethodTest(PowerMockTests.java:50)
has returned: "New Message from Mock!" (java.lang.String)
############ Logging method invocation #3 on mock/spy ########
ServiceMock.finalMessage();
invoked: -> at com.howtodoinjava.demo.powermock.PowerMockTests.mockFinalMethodTest(PowerMockTests.java:56)
has returned: "null"
8. Conclusion
In this powermock tutorial, we learned to setup the powermock with mockito and JUnit. we learned to mock and stub private, static and final methods in a class under test. Finally, we learned to verify the method invocations and the count of invocations including verbose logging.
Happy Learning !!