Leitfaden zu ReflectionTestUtils für Unit-Tests

1. Einleitung

ReflectionTestUtils ist Teil des Spring Test Context-Frameworks. Es handelt sich um eine Sammlung von reflexionsbasierten Dienstprogrammmethoden, die in einer Einheit verwendet werden, und Integrationstestszenarien zum Festlegen nicht öffentlicher Felder, Aufrufen nicht öffentlicher Methoden und Einfügen von Abhängigkeiten.

In diesem Tutorial sehen wir uns anhand mehrerer Beispiele an, wie wir die ReflectionTestUtils beim Testen von Einheiten verwenden können.

2. Maven-Abhängigkeiten

Beginnen wir damit, die neuesten Versionen aller für unsere Beispiele erforderlichen Abhängigkeiten zu unserer pom.xml hinzuzufügen :

 org.springframework spring-context 5.1.2.RELEASE   org.springframework spring-test 5.1.2.RELEASE test 

Die neuesten Spring-Kontext- und Spring-Test- Abhängigkeiten können aus dem Maven Central-Repository heruntergeladen werden.

3. Verwenden von ReflectionTestUtils zum Festlegen eines Werts für ein nicht öffentliches Feld

Angenommen, wir müssen in unserem Komponententest eine Instanz einer Klasse mit einem privaten Feld ohne öffentliche Setter-Methode verwenden.

Beginnen wir mit der Erstellung:

public class Employee { private Integer id; private String name; // standard getters/setters }

Normalerweise können wir nicht auf die private Feld- ID zugreifen , um einen Wert zum Testen zuzuweisen, da es keine öffentliche Setter-Methode dafür gibt.

Wir können dann die ReflectionTestUtils.setField- Methode verwenden, um der privaten Mitglieds- ID einen Wert zuzuweisen :

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

4. Verwenden von ReflectionTestUtils zum Aufrufen einer nicht öffentlichen Methode

Stellen wir uns nun vor, wir haben eine private Methode employeeToString in der Employee- Klasse:

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

Wir können einen Komponententest für die employeeToString- Methode wie folgt schreiben , obwohl sie keinen Zugriff von außerhalb einer Employee- Klasse hat:

@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. Verwenden von ReflectionTestUtils zum Injizieren von Abhängigkeiten

Angenommen , Sie möchten einen Komponententest für die folgende Spring-Komponente mit einem privaten Feld mit der Annotation @Autowired schreiben :

@Component public class EmployeeService { @Autowired private HRService hrService; public String findEmployeeStatus(Integer employeeId) { return "Employee " + employeeId + " status: " + hrService.getEmployeeStatus(employeeId); } }

Wir können die HRService- Komponente jetzt wie folgt implementieren :

@Component public class HRService { public String getEmployeeStatus(Integer employeeId) { return "Inactive"; } }

Lassen Sie uns außerdem mithilfe von Mockito eine Scheinimplementierung für die HRService- Klasse erstellen . Wir werden dieses Modell in die EmployeeService- Instanz einfügen und es in unserem Komponententest verwenden:

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

Da hrService ein privates Feld ohne öffentlichen Setter ist, verwenden wir die ReflectionTestUtils.setField- Methode, um den oben erstellten Mock in dieses private Feld einzufügen .

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

Schließlich wird unser Komponententest ungefähr so ​​aussehen:

@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())); }

Wir sollten beachten, dass diese Technik eine Problemumgehung für die Tatsache ist, dass wir in unserer Bohnenklasse die Feldinjektion verwenden. Wenn wir auf Konstruktorinjektion umsteigen würden, wäre dieser Ansatz nicht erforderlich.

6. Fazit

In diesem Tutorial haben wir anhand mehrerer Beispiele gezeigt, wie ReflectionTestUtils beim Testen von Einheiten verwendet wird.

Codebeispiele finden Sie wie immer auf Github.