본문 바로가기

Reactive stack

[Reactive stack] MVC에서 WebTestClient로 테스트 하기

최근 프로젝트를 webflux 환경에서 진행하면서, Restassured나 MockMVC 이외의 WebTestClient를 사용해서 테스트를 해보았습니다.

 

이미, WebClient를 사용하고 있어서 인지 WebTestClient가 Restassured와 MockMvc보다 직관적으로 느껴졌고 좋은 기억으로 남아있어서 다른 (MVC기반)프로젝트에서도 WebTestClient로 테스트를 해보고자 했습니다.


TL;DR

MVC에서 WebTestClient를 사용하는데는 성공했습니다. 하지만, WebTestClient는 Interceptor와 같은 MVC의 구성요소를 사용하기 힘듭니다. (Webflux에는 interceptor가 없어요.) 추가적으로, 자동구성이 아니라면기본적으로 등록되는 resolver (Pageable resolver 등)를 수동으로 다 등록해줘야합니다.

따라서, Webflux에서는 WebTestClient 를 사용하고 MVC에서는 Restassured 혹은 MockMVC를 사용하는게 좋아보입니다.


준비

WebClient를 비롯한 WebTestClient의 구현채는 모두 webflux 의존성에 포함되어 있습니다.

webflux없이도 WebTestClient 인터페이스나 @AutoConfigureWebTestClient 어노테이션을 확인할 수 있는데, 구현채가 없기때문에 적용해보면 사용할 수는 없습니다.

즉, webflux 의존성에는 해당 인터페이스의 구현채가 들어있고 WebTestClient를 사용하기 위해서는 webflux 의존성을 추가 해줘야 합니다.

저는 운영환경에서 webclient도 사용할것이기 때문에, testImplementation이 아닌, implementation으로 의존성을 추가해줬습니다.

implementation "org.springframework.boot:spring-boot-starter-webflux"

 

이때, 아래 사진과 같이 "mvc 와 webflux가 같이 있으면 어떻게 되는거지?" 라는 생각을 하실 수 있는데요, 스프링 톰캣이 있다면 톰캣을 우선적으로 실행시킵니다. 따라서, webflux로 추가되는 netty와 web으로 추가되는 tomcat 이 공존하므로 스프링은 tomcat을 실행시키고, one-request-per-one-thread 구조로 실행됩니다.

 

(추가적으로, MVC와 Webflux가 공존할때 스프링은 webflux의 DispatcherHandler가 아니라, mvc의 DispatcherServlet을 선택합니다.)

 

mvc vs webflux?

 


테스트 환경 구성

기존의 webflux 환경에서는 아래 사진과 같이 @AutoConfigureWebTestClient로 간단하게 WebTestClient를 등록할 수 있습니다.

 

AutoConfigureWebTestClient

 

하지만, 위 구성을 MVC 환경에서 적용해보면 ApplicationContext가 띄워지지조차 않습니다.

 

아래 사진은 @AutoConfigureWebTestClient가 실행하는 WebTestClientAutoConfiguration 클래스 입니다.

WebTestClient 구성을 보면, 58번째 줄에 WebTestClient.bindToApplicationContext 코드를 확인할 수 있습니다.

 

WebTestClientAutoConfiguration.webTestClient

 

여기까지는 별 문제가 없어보입니다. 하지만, WebTestClient.bindToApplicationContext로 바인딩된 결과는 DispatcherServlet이 아닌 DispatcherHandler를 등록받습니다. 따라서, MVC프로젝트에서 위 구성을 사용할 경우 DispatcherHandler를 찾을 수 없다는 에러를 발견하게 됩니다.

 

아래 사진은 bindToApplicationContext 메소드의 javadoc 중 일부입니다.

 

bindToApplicationContext - javadoc

 

 

따라서, 자동 구성은 사용할 수 없고, 위 코드와 비슷하게 WebTestClient를 등록해서 사용해주면 됩니다.

(아래부터는 다른 프로젝트라 Java 코드입니다.)

 

ApplicationContext를 등록하는 방법으로는 구성할 수 없으니, 직접 Controller를 주입해주겠습니다.

아래 코드와 같이 ApplicationContext에서 @Controller 어노테이션이 매핑된 빈을 모두 가져옵니다. 이때, @RestController또한, @Controller로 매핑되어있기 때문에, 같이 가져와 집니다. 

 

그 후, WebTestClient에 가져온 Controller를 전부 등록해주면 됩니다. (간단하죠?)

WebTestClient Mvc에서 사용하기

 

이렇게 구성하시면 아래와 같이, 성공적으로 테스트를 할 수 있습니다.

테스트 성공


결론

WebTestClient를 사용하면 편리하기 테스트를 작성할 수 있습니다.

Webflux환경에서는 WebTestClient를 사용하기 굉장히 편리하나, MVC 환경에서는 위 설정과 같이 추가적인 구성을 필요로 합니다.

 

개인적으로, MVC환경에서는 WebTestClient의 추가적인 구성 때문에 기존의 Restassured를 버리고 WebTestClient를 사용할 충분한 이유가 되지는 않는것 같습니다.

또한, 위 방식은 DispatcherServlet을 등록하는게 아닌 Controller를 등록하는 방식이기때문에, Interceptor 등 MVC의 많은 부분이 동작하지 않습니다. (Pageable 응답 자동변환 같은 것도 Resolver를 등록해줘야합니다.)

 

결론은.. MVC에서는 Restassured나 MockMvc를 사용합시다.