Ръководство за ReflectionTestUtils за единично тестване

1. Въведение

ReflectionTestUtils е част от контекста на Spring Test Context. Това е колекция за базирани на отражение полезни методи, използвани в единица, и сценарии за тестване на интеграция за задаване на непублични полета, извикване на непублични методи и инжекционни зависимости.

В този урок ще разгледаме как можем да използваме 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 class Employee { private Integer id; private String name; // standard getters/setters }

Обикновено не можем да осъществим достъп до идентификатора на частното поле, за да присвоим стойност за тестване, тъй като няма публичен метод за настройка за него.

След това можем да използваме ReflectionTestUtils.setField метод, за да присвоим стойност на идентификатора на частния член :

@Test public void whenNonPublicField_thenReflectionTestUtilsSetField() { Employee employee = new Employee(); ReflectionTestUtils.setField(employee, "id", 1); assertTrue(employee.getId().equals(1)); }

4. Използване на ReflectionTestUtils за извикване на непубличен метод

Нека сега си представим, че имаме частен метод workerToString в клас Employee :

private String employeeToString(){ return "id: " + getId() + "; name: " + getName(); }

Можем да напишем единица тест за employeeToString метод, както по-долу, въпреки че той не разполага с достъп отвън на служителите клас:

@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"; } }

Освен това, нека създадем фиктивна реализация за класа HRService, като използваме Mockito. Ще инжектираме този макет в екземпляра EmployeeService и ще го използваме в нашия тестов модул:

HRService hrService = mock(HRService.class); when(hrService.getEmployeeStatus(employee.getId())).thenReturn("Active");

Тъй като hrService е частно поле без публичен сетер, ние ще използваме метода 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())); }

Трябва да отбележим, че тази техника е заобиколно решение за факта, че използваме полево инжектиране в нашия клас боб. Ако преминем към инжектиране на конструктор, тогава този подход не би бил необходим.

6. Заключение

В този урок показахме как да използваме ReflectionTestUtils в модулно тестване, като разгледаме няколко примера.

Примери за кодове, както винаги, можете да намерите в Github.