Spring은 어떻게 테스트 환경에 맞는 WebTestClient를 자동 주입해주는걸까?

viiviii·2023년 4월 11일
1
post-thumbnail

🚨 해당 글은 Spring MVC, Spring boot 3.0 기준으로 작성됨

최근 문서를 살펴보다 스프링 부트에서 WebTestClient는 라이브 서버와 모의 환경 모두에서 사용할 수 있다는 문구를 보게 됐다.

사용 코드는 아래와 같았고 (webflux 의존성 추가 필요)

// Bind to Server
client = WebTestClient.bindToServer()
        .baseUrl("http://localhost:8080")
        .build();

// Bind to ApplicationContext
client = MockMvcWebTestClient.bindToApplicationContext(wac)
        .build();

실제로 테스트해 보니 잘 동작했다.

그런데 어떻게 자동 주입 시 WebTestClient를 각각의 테스트에 맞춰서 주입해 주는 걸까?

어떻게

결론부터 말하면,

Spring에는 Test Context를 커스텀 할 수 있는 ContextCustomizer interface가 있는데 WebTestClient도 이걸 구현했고, 이 구현체와 테스트 어노테이션을 통해 실행 환경에 따른 맞춤형 주입을 해준다.

  • 서버 환경 👉 WebTestClient.bindToServer()
  • 모의 환경 👉 MockMvcWebTestClient.bindTo(mockMvc)

자세히

Spring Test에서 customizer 동작

  1. Test context가 로드될 때 factory를 통해 모든 customizer를 생성한다
  2. 그 후 루프를 돌며 customizer의 customizeContext() 메서드를 호출한다

실제 WebTestClient 구현체의 동작

  1. factory가 customizer를 생성할 때 ✅@SpringBootTest에서 ✅WebClient를 사용하는 경우에만 customizer를 생성한다.

  1. 이후 호출된 customizer에서 ✅실행 환경이 서버인 경우에만 WebTestClientbean으로 등록한다.

그래서 위 조건을 충족하는 실행 환경이 서버인 테스트는 customizer가 bindToServer()WebTestClient를 bean으로 등록하는 것이다.

  • @SpringBootTest(webEnvironment = RANDOM_PORT)
  • @SpringBootTest(webEnvironment = DEFINED_PORT)

💡 참고로 위 이미지에서 환경에서 설정된 포트를 가져오는 코드 덕분에 설정한 RANDOM_PORTDEFINED_PORT도 함께 자동 설정되는 것이다.

그럼 위 조건을 충족하지 않은 다른 테스트들은 어떻게 생성된 것일까?

  • @SpringBootTest @AutoConfigureMockMvc
  • @WebMvcTest

그건 @AutoConfigureMockMvc에 의해 호출되는 MockMvcAutoConfigurationmockMvc로 WebTestClient를 생성해 bean으로 등록해 주기 때문이다.

💡@WebMvcTest도 내부적으로@AutoConfigureMockMvc갖고 있다.

어떻게 WebTestClient는 둘 다 사용 가능한걸까?

위에서 알게된 MockMvcWebTestClientbindTo() 동작을 보면 알 수 있다.

mockMvc를 ClienHttpConnet로 만들어서 서버인 것 처럼 사용하기 때문이다.

static WebTestClient.Builder bindTo(MockMvc mockMvc) {
    ClientHttpConnector connector = new MockMvcHttpConnector(mockMvc);
    return WebTestClient.bindToServer(connector);
}

구현체인 MockMvcHttpConnector가 HTTP를 통해 실제 요청을 하는 대신 MockMvc를 호출하여 요청을 처리한다고 한다.

2개의 댓글

comment-user-thumbnail
2023년 10월 17일

ContextCustomizer 라는게 있는 지 처음 알았네요!

1개의 답글