Рубрики
Без рубрики

Руководство по рефлекторным тестам для модульного тестирования

Узнайте, как использовать ReflectionTestUtils в модульном тестировании, просмотрев несколько примеров.

Автор оригинала: baeldung.

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 .