1. Introduction
ReflectionTestUtils is a part of the Spring Test Context framework. Itβs a collection for reflection-based utility methods used in a unit, and integration testing scenarios to set the non-public fields, invoke non-public methods, and inject dependencies.
In this tutorial, weβll learn how to use ReflectionTestUtils in unit testing by going through several examples.
2. Maven Dependencies
Weβll start by adding the latest versions of all the necessary dependencies to our pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
The latest spring-context and spring-test dependencies can be downloaded from the Maven Central repository.
3. Using ReflectionTestUtils to Set a Value of a Non-Public Field
Suppose we need to use an instance of a class having a private field, without a public setter method in our unit test.
Weβll start by creating it:
public class Employee {
private Integer id;
private String name;
// standard getters/setters
}
Normally we canβt access the private field id to assign a value for testing because there isnβt a public setter method for it.
So weβll use the ReflectionTestUtils.setField method to assign a value to the private member id:
@Test
public void whenNonPublicField_thenReflectionTestUtilsSetField() {
Employee employee = new Employee();
ReflectionTestUtils.setField(employee, "id", 1);
assertTrue(employee.getId().equals(1));
}
4. Using ReflectionTestUtils to Invoke a Non-Public Method
Now letβs imagine that we have a private method, employeeToString, in the Employee class:
private String employeeToString(){
return "id: " + getId() + "; name: " + getName();
}
We can write a unit test for the employeeToString method as below, even though it doesnβt have any access from outside of an Employee class:
@Test
public void whenNonPublicMethod_thenReflectionTestUtilsInvokeMethod() {
Employee employee = new Employee();
ReflectionTestUtils.setField(employee, "id", 1);
employee.setName("Smith, John");
assertTrue(ReflectionTestUtils.invokeMethod(employee, "employeeToString")
.equals("id: 1; name: Smith, John"));
}
5. Using ReflectionTestUtils to Inject Dependencies
Letβs say we want to write a unit test for the following Spring component having a private field with the @Autowired annotation:
@Component
public class EmployeeService {
@Autowired
private HRService hrService;
public String findEmployeeStatus(Integer employeeId) {
return "Employee " + employeeId + " status: " + hrService.getEmployeeStatus(employeeId);
}
}
Now we can implement the HRService component as below:
@Component
public class HRService {
public String getEmployeeStatus(Integer employeeId) {
return "Inactive";
}
}
Furthermore, weβll create a mock implementation for the HRService class by using Mockito. Weβll inject this mock into the EmployeeService instance, and weβll use it in our unit test:
HRService hrService = mock(HRService.class);
when(hrService.getEmployeeStatus(employee.getId())).thenReturn("Active");
Because hrService is a private field without a public setter, weβll use the ReflectionTestUtils.setField method to inject the mock we created above into this private field:
EmployeeService employeeService = new EmployeeService();
ReflectionTestUtils.setField(employeeService, "hrService", hrService);
Finally, our unit test will look similar to this:
@Test
public void whenInjectingMockOfDependency_thenReflectionTestUtilsSetField() {
Employee employee = new Employee();
ReflectionTestUtils.setField(employee, "id", 1);
employee.setName("Smith, John");
HRService hrService = mock(HRService.class);
when(hrService.getEmployeeStatus(employee.getId())).thenReturn("Active");
EmployeeService employeeService = new EmployeeService();
// Inject mock into the private field
ReflectionTestUtils.setField(employeeService, "hrService", hrService);
assertEquals(
"Employee " + employee.getId() + " status: Active",
employeeService.findEmployeeStatus(employee.getId()));
}
We should note that this technique is a workaround for the fact that weβre using field injection in our bean class. If we switched to constructor injection, then this approach wouldnβt be necessary.
6. Conclusion
In this article, we demonstrated how to use ReflectionTestUtils in unit testing by going through several examples.
