1. 소개
ReflectionTestUtils 는 Spring Test Context 프레임워크의 일부입니다. 이는 단위에서 사용되는 리플렉션 기반 유틸리티 메서드의 모음이며, 비공개 필드를 설정하고 비공개 메서드를 호출하고 의존성을 주입하기 위한 통합 테스트 시나리오입니다.
이 사용방법(예제)에서는 몇 가지 예제를 통해 단위 테스트에서 ReflectionTestUtils 를 사용하는 방법을 배웁니다.
2. 메이븐 의존성
필요한 모든 의존성의 최신 버전을 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>
최신 스프링 컨텍스트 및 스프링 테스트 의존성은 Maven Central 저장소에서 다운로드할 수 있습니다.
3. ReflectionTestUtils 를 사용하여 비공개 필드 값 설정
단위 테스트에서 공용 setter 메서드 없이 개인 필드가 있는 클래스의 인스턴스를 사용해야 한다고 가정합니다.
생성부터 시작하겠습니다.
public class Employee {
private Integer id;
private String name;
// standard getters/setters
}
일반적으로 공개 setter 메서드가 없기 때문에 테스트용 값을 할당하기 위해 비공개 필드 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 클래스 에 private 메서드인 employeeToString 이 있다고 가정해 보겠습니다 .
private String employeeToString(){
return "id: " + getId() + "; name: " + getName();
}
Employee 클래스 외부에서 액세스할 수 없는 경우에도 아래와 같이 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 를 사용하여 의존성 주입
@Autowired 어노테이션 이 있는 개인 필드가 있는 다음 Spring 구성 요소에 대한 단위 테스트를 작성한다고 가정해 보겠습니다 .
@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";
}
}
또한 Mockito 를 사용하여 HRService 클래스에 대한 모의 구현을 생성합니다 . 이 모형을 EmployeeService 인스턴스 에 주입 하고 단위 테스트에서 사용할 것입니다.
HRService hrService = mock(HRService.class);
when(hrService.getEmployeeStatus(employee.getId())).thenReturn("Active");
hrService 는 공개 setter가 없는 비공개 필드이므로 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 에서 찾을 수 있습니다 .