
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: January 8, 2024
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.
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>2.0.9</version>
<scope>test</scope>
</dependency>
The latest versions can be checked here and here.
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());
}
For exhaustive unit testing of the method, we’d need to mock private methods.
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.
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.
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());
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.
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.