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 에서 찾을 수 있습니다 .

Junit footer banner