Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Annotated Controllers: Spring Web/WebFlux and Testing

DZone's Guide to

Annotated Controllers: Spring Web/WebFlux and Testing

Spring Web and Spring WebFlux have similar names, so testing should be similar too, right? Guess again. See how these web stacks differ for testing.

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

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:

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, that can be specified using a Gradle build file in the following way:

compile('org.springframework.boot:spring-boot-starter-web')


Then, the test of such an endpoint would use a mock web runtime, referred to as Mock MVC:

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 WebFlux

If, on the other hand, Spring-WebFlux starters were pulled in, say with the following Gradle dependency...

compile('org.springframework.boot:spring-boot-starter-webflux')


...then the test of this endpoint would use the excellent WebTestClient class, along these lines:

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 when using the 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 developers, we have to be mindful of the underlying stack that comes into play and formulate tests accordingly. I hope this post clarifies how such a test should be crafted.

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
java ,spring webflux ,annotations ,controller ,testing ,spring web ,tutorial

Published at DZone with permission of Biju Kunjummen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}