Annotated controllers – Spring Web/Webflux and Testing
Spring Webflux and Spring Web are two entirely different web stacks. Spring Webflux, however, continues to support an annotation-based programming model
An endpoint defined using these two stacks may look similar but the way to test such an endpoint is fairly different and a user writing such an endpoint has to be aware of which stack is active and formulate the test accordingly.
Sample Endpoint
Consider a sample annotation based endpoint:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController data class Greeting(val message: String) @RestController @RequestMapping ( "/web" ) class GreetingController { @PostMapping ( "/greet" ) fun handleGreeting( @RequestBody greeting: Greeting): Greeting { return Greeting( "Thanks: ${greeting.message}" ) } } |
Testing with Spring Web
If Spring Boot 2 starters were used to create this application with Spring Web as the starter, specified using a Gradle build file the following way:
1 | compile( 'org.springframework.boot:spring-boot-starter-web' ) |
then the test of such an endpoint would be using a Mock web runtime, referred to as Mock MVC:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.test.context.junit4.SpringRunner import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content @RunWith (SpringRunner:: class ) @WebMvcTest (GreetingController:: class ) class GreetingControllerMockMvcTest { @Autowired lateinit var mockMvc: MockMvc @Test fun testHandleGreetings() { mockMvc .perform( post( "/web/greet" ) .content( "" " |{ | "message" : "Hello Web" |} "" ".trimMargin()) ).andExpect(content().json( "" " |{ | "message" : "Thanks: Hello Web" |} "" ".trimMargin())) } } |
Testing with Spring Web-Flux
If on the other hand Spring-Webflux starters were pulled in, say with the following Gradle dependency:
1 | compile( 'org.springframework.boot:spring-boot-starter-webflux' ) |
then the test of this endpoint would be using the excellent WebTestClient class, along these lines:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest import org.springframework.http.HttpHeaders import org.springframework.test.context.junit4.SpringRunner import org.springframework.test.web.reactive.server.WebTestClient import org.springframework.web.reactive.function.BodyInserters @RunWith (SpringRunner:: class ) @WebFluxTest (GreetingController:: class ) class GreetingControllerTest { @Autowired lateinit var webTestClient: WebTestClient @Test fun testHandleGreetings() { webTestClient.post() .uri( "/web/greet" ) .header(HttpHeaders.CONTENT_TYPE, "application/json" ) .body(BodyInserters .fromObject( "" " |{ | "message" : "Hello Web" |} "" ".trimMargin())) .exchange() .expectStatus().isOk .expectBody() .json( "" " |{ | "message" : "Thanks: Hello Web" |} "" ".trimMargin()) } } |
Conclusion
It is easy to assume that since the programming model looks very similar using Spring Web and Spring Webflux stacks, that the tests for such a legacy test using Spring Web would continue over to Spring Webflux, this is however not true, as a developer we have to be mindful of the underlying stack that comes into play and formulate the test accordingly. I hope this post clarifies how such a test should be crafted.
Published on Java Code Geeks with permission by Biju Kunjummen, partner at our JCG program. See the original article here: Annotated controllers – Spring Web/Webflux and Testing Opinions expressed by Java Code Geeks contributors are their own. |