1. Overview
One of the challenges of unit testing is mocking private methods.
In this tutorial, we’ll learn about how we can achieve this by using the PowerMock library – which is supported by JUnit and TestNG.
PowerMock integrates with mocking frameworks like EasyMock and Mockito and is meant to add additional functionality to these – such as mocking private methods, final classes, and final methods, etc.
It does that by relying on bytecode manipulation and an entirely separate classloader.
2. Maven Dependencies
First, let’s add required dependencies to use PowerMock with Mockito and JUnit into our pom.xml:
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.7.3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>1.7.3</version> <scope>test</scope> </dependency>
The latest versions can be checked here and here.
3. Example
Let’s get started with an example of a LuckyNumberGenerator. This class has a single public method for generating a lucky number:
public int getLuckyNumber(String name) { saveIntoDatabase(name); if (name == null) { return getDefaultLuckyNumber(); } return getComputedLuckyNumber(name.length()); }
4. Variations in Mocking of Private Methods
For exhaustive unit testing of the method, we’d need to mock private methods.
4.1. Method with No Arguments but with Return Value
As a simple example, let’s mock the behavior of a private method with no arguments and force it to return the desired value:
LuckyNumberGenerator mock = spy(new LuckyNumberGenerator()); when(mock, "getDefaultLuckyNumber").thenReturn(300);
In this case, we mock the private method getDefaultLuckyNumber and make it return a value of 300.
4.2. Method with Argument and Return Value
Next, let’s mock the behavior of a private method with an argument and force it to return the desired value:
LuckyNumberGenerator mock = spy(new LuckyNumberGenerator()); doReturn(1).when(mock, "getComputedLuckyNumber", ArgumentMatchers.anyInt());
In this case, we mock the private method and make it return 1.
Notice that we don’t care about the input argument and use ArgumentMatchers.anyInt() as a wildcard.
4.3. Verification of Invocation of a Method
Our final strategy is to use PowerMock to verify the invocation of a private method:
LuckyNumberGenerator mock = spy(new LuckyNumberGenerator()); int result = mock.getLuckyNumber("Tyranosorous"); verifyPrivate(mock).invoke("saveIntoDatabase", ArgumentMatchers.anyString());
5. A Word of Caution
Finally, although private methods can be tested using PowerMock, we must be extra cautious while using this technique.
Given the intent of our testing is to validate the behavior of a class, we should refrain from changing the internal behavior of the class during unit testing.
Mocking techniques should be applied to the external dependencies of the class and not to the class itself.
If mocking of private methods is essential for testing our classes, it usually indicates a bad design.
6. Conclusion
In this quick article, we showed how PowerMock could be used to extend the capability of Mockito for mocking and verification of private methods in the class under test.
The source code of this tutorial can be found over on GitHub.