JUnit 5 의존성 주입 과정에서의 문제

문제상황

@ActiveProfiles("test")
@SpringBootTest
//@SpringBootTest: 전체 Spring 애플리케이션 컨텍스트를 로드
@AutoConfigureMockMvc
//AutoConfigureMockMvc: MockMvc 인스턴스를 자동 구성하는 데 사용됩니다.
//MockMvc는 Spring MVC 애플리케이션의 컨트롤러를 테스트하기 위한 주요 도구입니다. 이를 사용하여 HTTP 요청을 보내고 응답을 검증할 수 있습니다.
public class ControllerTest {

    MockMvc mockMvc;

    @BeforeEach
    public void setUp(WebApplicationContext applicationContext) {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(applicationContext).build();
    }
 ...
 }
  • 위 코드는 생성자 주입이나 필드주입의 경우가 아닌데도 불구하고 주입이 되어서 테스트가 성공적으로 돌아가고 있었습니다
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {

    MockMvc mockMvc;
    Repository repository;
    
    @BeforeEach
    public void setUp(WebApplicationContext applicationContext, Repository repository) {
    	this.repository=repository;
        this.mockMvc = MockMvcBuilders.webAppContextSetup(applicationContext).build();
    }
 ...
 }
  •  하지만 Repository코드를 다음과 같이 추가한다고 하면 No ParameterResolver registered for parameter 과 같은 오류가 뜨면서 테스트가 실패하였습니다
  • 해당 오류는 일반적으로 JUnit이 처리 방법을 모르는 매개변수가 있는 테스트 클래스의 생성자나 메소드를 사용하려고 할 때 JUnit 5에서 발생합니다. 

문제원인

  • 공식문서에서는 다음과 같이 정의하고 있습니다
ParameterResolver는 런타임 시 매개변수에 대한 인수를 동적으로 확인하려는 확장용 API를 정의합니다.
테스트 클래스의 생성자 또는 @Test, @BeforeEach, @AfterEach, @BeforeAll 또는 @AfterAll 메서드가 매개 변수를 선언하는 경우 매개 변수에 대한 인수는 런타임 시 ParameterResolver에 의해 확인되어야 합니다.
public interface ParameterResolver extends Extension {

	boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
			throws ParameterResolutionException;

	Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
			throws ParameterResolutionException;

}
  • supportsParameter(ParameterContext, ExtensionContext): 이 메소드는 주어진 ParameterContext와 ExtensionContext에 대해 이 리졸버가 매개변수의 인자를 지원하는지를 결정합니다. 즉, 특정 매개변수를 해결할 수 있는지 여부를 판단합니다.
  • resolveParameter(ParameterContext, ExtensionContext): 이 메소드는 supportsParameter 메소드가 true를 반환한 경우에만 프레임워크에 의해 호출됩니다. 매개변수에 대한 인자를 제공하여 반환합니다. 
  • 또한 JUnit 5에서는 테스트 메소드나 라이프사이클 메소드(예: @BeforeEach)의 매개변수가 Spring처럼 자동으로 주입되지 않습니다. 대신 JUnit 5는 ParameterResolver 구현을 사용하여 매개변수를 확인합니다. 이는 매개변수가 주입되려면 이를 지원하는 해당 ParameterResolver가 있어야 함을 의미합니다.
If a test class constructor, test method, or lifecycle method (see Definitions) declares a parameter, the parameter must be resolved at runtime by a ParameterResolver. A ParameterResolver can either be built-in (see TestInfoParameterResolver) or registered by the user. Generally speaking, parameters may be resolved by name, type, annotation, or any combination thereof.
<번역>
테스트 클래스 생성자, 테스트 메서드 또는 수명 주기 메서드(정의 참조)가 매개 변수를 선언하는 경우 해당 매개 변수는 런타임 시 ParameterResolver에 의해 확인되어야 합니다. ParameterResolver는 내장되어 있거나(TestInfoParameterResolver 참조) 사용자가 등록할 수 있습니다. 일반적으로 매개변수는 이름, 유형, 주석 또는 이들의 조합으로 분석될 수 있습니다.
  • 공식문서의 내용을 인용한 내용입니다
  • 위의 내용에 따르면, ParameterResolver은 미리 등록된 요소에 한에서만 주입이 되는것으로 보입니다
  • 따라서, 기본적으로 일부 잘 알려진 타입(예: WebApplicationContext)에 대해서만 주입을 지원해서 사용자 정의 컴포넌트는 지원되지 않는 것 같습니다.

결론

  • @autowired을 쓰면 스프링이 주입을 해주지만, 메서드 매개변수에 대해서는 junit이 ParameterResolver을 사용하여 매개변수를 주입합니다.
  • JUnit 5는 기본적으로 일부 잘 알려진 타입(예: WebApplicationContext)에 대해서만 주입을 지원해서 사용자 정의 컴포넌트는 지원되지 않는 것 같습니다.

https://junit.org/junit5/docs/5.7.0/api/org.junit.jupiter.api/org/junit/jupiter/api/extension/ParameterResolver.html

https://junit.org/junit5/docs/current/user-guide/#extensions-parameter-resolution