Guide de ReflectionTestUtils pour les tests unitaires

1. Introduction

ReflectionTestUtils fait partie du cadre de contexte Spring Test. Il s’agit d’un ensemble de méthodes utilitaires basées sur la réflexion utilisées dans une unité et de scénarios de test d’intégration permettant de définir les champs non publics, d’appeler des méthodes non publiques et d’injecter des dépendances.

Dans ce didacticiel, nous verrons comment utiliser le ReflectionTestUtils dans les tests unitaires en prenant plusieurs exemples.

2. Dépendances Maven

Commençons par ajouter les dernières versions de toutes les dépendances nécessaires à nos exemples dans notre 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>

Le dernier __https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.springframework%22%20AND%20a%3A%22spring-context%22[spring-context], spring-test __dépendances peuvent être téléchargées à partir de Maven Référentiel central.

3. Utilisation de ReflectionTestUtils pour définir la valeur d’un champ non public

Supposons que nous ayons besoin d’utiliser une instance d’une classe ayant un champ privé sans méthode de définition publique dans notre test unitaire.

Commençons par le créer:

public class Employee {
    private Integer id;
    private String name;

   //standard getters/setters
}

Normalement, nous ne pouvons pas accéder au champ privé id pour attribuer une valeur à tester, car il n’existe pas de méthode de définition publique.

Nous pouvons ensuite utiliser la méthode ReflectionTestUtils.setField pour affecter une valeur au membre privé id :

@Test
public void whenNonPublicField__thenReflectionTestUtilsSetField() {
    Employee employee = new Employee();
    ReflectionTestUtils.setField(employee, "id", 1);

    assertTrue(employee.getId().equals(1));
}

4. Utilisation de ReflectionTestUtils pour appeler une méthode non publique

Imaginons maintenant que nous avons une méthode privée employeeToString dans Employee class:

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

Nous pouvons écrire un test unitaire pour la méthode employeeToString comme ci-dessous, même si elle n’a aucun accès depuis une classe 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. Utilisation de ReflectionTestUtils pour injecter des dépendances

Disons que vous voulez écrire un test unitaire pour le composant Spring suivant ayant un champ privé avec l’annotation @ Autowired :

@Component
public class EmployeeService {

    @Autowired
    private HRService hrService;

    public String findEmployeeStatus(Integer employeeId) {
        return "Employee " + employeeId + " status: " + hrService.getEmployeeStatus(employeeId);
    }
}

Nous pouvons maintenant implémenter le composant HRService comme ci-dessous:

@Component
public class HRService {

    public String getEmployeeStatus(Integer employeeId) {
        return "Inactive";
    }
}

De plus, créons une implémentation fictive pour la classe HRService en utilisant Mockito .

Nous allons injecter cette maquette dans l’instance EmployeeService et l’utiliser dans notre test unitaire:

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

Étant donné que hrService est un champ privé sans un ouvreur public, nous allons utiliser la méthode ReflectionTestUtils.setField pour injecter la maquette créée précédemment dans ce champ privé.

EmployeeService employeeService = new EmployeeService();
ReflectionTestUtils.setField(employeeService, "hrService", hrService);

Enfin, notre test unitaire ressemblera à ceci:

@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. Conclusion

Dans ce tutoriel, nous avons montré comment utiliser ReflectionTestUtils dans les tests unitaires en prenant plusieurs exemples.

Comme d’habitude, vous trouverez des exemples de code à l’adresse over sur Github .