1. введение
ReflectionTestUtils является частью контекстного фреймворка Spring Test. Это коллекция служебных методов на основе отражения, используемых в модуле, и сценариев интеграционного тестирования для установки непубличных полей, вызова непубличных методов и внедрения зависимостей.
В этом уроке мы рассмотрим, как мы можем использовать ReflectionTestUtils в модульном тестировании, пройдя несколько примеров.
2. Зависимости Maven
Давайте начнем с добавления последних версий всех необходимых зависимостей, необходимых для наших примеров, в наш pom.xml :
org.springframework spring-context 5.1.2.RELEASE org.springframework spring-test 5.1.2.RELEASE test
Последние зависимости spring-context , spring-test можно загрузить из центрального репозитория Maven.
3. Использование ReflectionTestUtils для установки значения непубличного поля
Предположим, нам нужно использовать экземпляр класса, имеющего закрытое поле, без метода public setter в нашем модульном тесте.
Давайте начнем с его создания:
public class Employee { private Integer id; private String name; // standard getters/setters }
Обычно мы не можем получить доступ к закрытому полю id , чтобы присвоить значение для тестирования, потому что для него нет общедоступного метода настройки.
Затем мы можем использовать метод ReflectionTestUtils.SetField для присвоения значения частному члену id :
@Test public void whenNonPublicField_thenReflectionTestUtilsSetField() { Employee employee = new Employee(); ReflectionTestUtils.setField(employee, "id", 1); assertTrue(employee.getId().equals(1)); }
4. Использование ReflectionTestUtils для вызова непубличного метода
Давайте теперь представим, что у нас есть частный метод employee toString в Employee классе:
private String employeeToString(){ return "id: " + getId() + "; name: " + getName(); }
Мы можем написать модульный тест для метода employee toString , как показано ниже, даже если он не имеет доступа извне класса Employee :
@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. Использование ReflectionTestUtils для введения зависимостей
Допустим, вы хотите написать модульный тест для следующего компонента Spring, имеющего частное поле с аннотацией @Autowired :
@Component public class EmployeeService { @Autowired private HRService hrService; public String findEmployeeStatus(Integer employeeId) { return "Employee " + employeeId + " status: " + hrService.getEmployeeStatus(employeeId); } }
Теперь мы можем реализовать компонент HRService , как показано ниже:
@Component public class HRService { public String getEmployeeStatus(Integer employeeId) { return "Inactive"; } }
Кроме того, давайте создадим макет реализации для класса HR Service с помощью Mockito . Мы введем макет в экземпляр Employee Service и будем использовать его в нашем модульном тесте:
HRService hrService = mock(HRService.class); when(hrService.getEmployeeStatus(employee.getId())).thenReturn("Active");
Поскольку hr Service является закрытым полем без публичного сеттера, мы будем использовать метод ReflectionTestUtils.SetField , чтобы ввести макет, созданный выше, в это закрытое поле.
EmployeeService employeeService = new EmployeeService(); ReflectionTestUtils.setField(employeeService, "hrService", hrService);
Наконец, наш модульный тест будет выглядеть примерно так:
@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())); }
Мы должны отметить, что этот метод является обходным путем для того факта, что мы используем инъекцию полей в нашем классе bean. Если бы мы переключились на инъекцию конструктора, то такой подход не был бы необходим.
6. Заключение
В этом уроке мы показали, как использовать ReflectionTestUtils в модульном тестировании, пройдя несколько примеров.
Примеры кода, как всегда, можно найти на Github .