How to test Private Methods using Junit 5
Junit Private Method
Here in this tutorial I will show you an example on how to test private methods using Junit framework.
I am using Junit 5 framework to test the private method. Using Mockito framework you won’t be able to test private methods, but using PowerMock core API you will be able to test the private methods. You can also use Java’s Reflection API to test private methods. You can use Spring framework’sReflectionTestUtils to test your private methods.You generally don’t want to unit test private methods directly. Since they are private, you would consider them to call from a public method. If the methods that call your private methods are working as you expect, you then assume by extension that your private methods are working correctly. But still I will show you here how to unit test your private methods in Java and Spring applications.
Prerequisites
Java 12/22, Junit 5, PowerMock Core, Mockito Core, Spring Boot Starter Test
Test Private Method in Java App
Project Setup
For the recent version of Java 22 with Mockito Core (without PowerMock) you can refer to the following pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roytuts</groupId>
<artifactId>java-junit-mock-private-methods</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>22</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.13.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.18.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.18.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> For Java version 12, you need to configure the following pom.xml file for maven based project:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roytuts</groupId>
<artifactId>java-junit-mock-private-methods</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Private Method
First I am going to test private method in Java based application. Consider the following class where I have created a private method called pvMethod().
package com.roytuts.java.junit.mock;
public class PrivateMethodApp {
private Integer pvMethod(Integer id) {
System.out.println(id + 10);
return id + 10;
}
}
Note important thing is that if you are using Java’s reflection API to test your private method then arguments to the private methods need to be of object class types instead of primitive types. For example, I have used Integer instead of int.
Junit Class
For Java version 22, use the following Junit test class:
package com.roytuts.java.junit.mock;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.commons.util.ReflectionUtils;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class PrivateMethodTest {
@Mock
private PrivateMethodApp app;
//@InjectMocks
//private PrivateMethodApp app = new PrivateMethodApp();
@Test
public void testPrivateMethodUsingReflection() throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method method = PrivateMethodApp.class.getDeclaredMethod("pvMethod", Integer.class);
method.setAccessible(true);
method.invoke(app, 10);
}
@Test
public void testPrivateMethodUsingReflectionUtils() throws Exception {
Method method = PrivateMethodApp.class.getDeclaredMethod("pvMethod", Integer.class);
ReflectionUtils.invokeMethod(method, app, 10);
}
} Next I am going to create the following Junit test class for Java version 12 to test the above private method.
package com.roytuts.java.junit.mock;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.powermock.reflect.Whitebox;
@ExtendWith(MockitoExtension.class)
public class PrivateMethodTest {
// @Mock
// private PrivateMethodApp app;
@InjectMocks
private PrivateMethodApp app = new PrivateMethodApp();
@Test
public void testPrivateMethodUsingReflection() throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method method = PrivateMethodApp.class.getDeclaredMethod("pvMethod", Integer.class);
method.setAccessible(true);
method.invoke(app, 10);
}
@Test
public void testPrivateMethodUsingPowerMock() throws Exception {
Whitebox.invokeMethod(app, "pvMethod", 10);
}
}
To create the mock instance of the PrivateMethodApp, you can use either @Mock or @InjectMocks annotation.
Finally I have created two methods and annotated with @Test annotation to test the private method. testPrivateMethodUsingReflection() – tests using Java’s reflection API and make sure you need to have the class types for the method arguments. testPrivateMethodUsingPowerMock() – tests using PowerMock API and you can have class or primitive types for method arguments.
testPrivateMethodUsingReflectionUtils() – tests using Junit’s ReflectionUtils class as you won’t be able to use PowerMock library in Java version 22.
Executing the above test class will pass the Junit test class.
Test Private Method in Spring App
Now I will show you how to test private method using Spring’s ReflectionTestUtils API.
Project Setup
For Spring Boot 3.5.4 version, you can use the following pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roytuts</groupId>
<artifactId>spring-junit-mock-private-method</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>22</maven.compiler.release>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.4</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> You can refer to the following pom.xml file for Spring Boot version 2.4.5. You need to add the Spring Boot starter and starter test dependencies into the pom.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roytuts</groupId>
<artifactId>java-junit-mock-private-methods</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Junit Class
Next I am going to add new test method in the PrivateMethodTest class to test private method using ReflectionTestUtils.
package com.roytuts.java.junit.mock;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;
@ExtendWith(MockitoExtension.class)
public class PrivateMethodTest {
// @Mock
// private PrivateMethodApp app;
@InjectMocks
private PrivateMethodApp app = new PrivateMethodApp();
@Test
public void testPrivateMethodUsingReflectionUtils() throws Exception {
ReflectionTestUtils.invokeMethod(app, "pvMethod", 10);
}
} Executing the above test class will pass the Junit test case.
That’s an idea how to test your private methods in Java and Spring applications.
No comments
Leave a comment