🚨 해당 글은 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)
@SpringBootTest
에서 ✅WebClient를 사용
하는 경우에만 customizer를 생성한다.실행 환경이 서버
인 경우에만 WebTestClient
를 bean으로 등록한다.그래서 위 조건을 충족하는 실행 환경이 서버인 테스트는 customizer가 bindToServer()로 WebTestClient
를 bean으로 등록하는 것이다.
@SpringBootTest(webEnvironment = RANDOM_PORT)
@SpringBootTest(webEnvironment = DEFINED_PORT)
💡 참고로 위 이미지에서 환경에서 설정된 포트를 가져오는 코드 덕분에 설정한
RANDOM_PORT
나DEFINED_PORT
도 함께 자동 설정되는 것이다.
그럼 위 조건을 충족하지 않은 다른 테스트들은 어떻게 생성된 것일까?
@SpringBootTest
@AutoConfigureMockMvc
@WebMvcTest
그건 @AutoConfigureMockMvc
에 의해 호출되는 MockMvcAutoConfiguration
가 mockMvc로 WebTestClient
를 생성해 bean으로 등록해 주기 때문이다.
💡
@WebMvcTest
도 내부적으로@AutoConfigureMockMvc
를 갖고 있다.
위에서 알게된 MockMvcWebTestClient
의 bindTo() 동작을 보면 알 수 있다.
mockMvc를 ClienHttpConnet로 만들어서 서버인 것 처럼 사용하기 때문이다.
static WebTestClient.Builder bindTo(MockMvc mockMvc) {
ClientHttpConnector connector = new MockMvcHttpConnector(mockMvc);
return WebTestClient.bindToServer(connector);
}
구현체인 MockMvcHttpConnector가 HTTP를 통해 실제 요청을 하는 대신 MockMvc를 호출하여 요청을 처리한다고 한다.
ContextCustomizer 라는게 있는 지 처음 알았네요!