
🚨 해당 글은 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 라는게 있는 지 처음 알았네요!