membersound
membersound

Reputation: 86747

How to validate Exception in spring-webflux WebTestClient tests?

How can I validate the actual Exception in a spring-webflux test? The following worked in the old spring-web environment, but migrating to netty and spring-webflux, the MvcResult cannot be resolved anymore (NullPointerException):

@SpringBootTest
@AutoConfigureWebTestClient
public class ApiTest {
    @Test
    public void test() throws Exception {
        webTestClient.get()
                .uri("/api?test=123")
                .exchange()
                .expectStatus().isBadRequest()
                .expectBody().consumeWith(rsp -> {
                     //throws NPE
                    Exception ex = ((MvcResult) rsp.getMockServerResult()).getResolvedException();
                    assertTrue(ex instanceof ResponseStatusException);
                });
    }
}

@RestController 
public class ApiController {
   @PostMapping("/api")
   public String test(@RequestParam String test) {
      if (test.matches("[0-9]+"))
         throw new ResponseStatusException(HttpStatus.BadRequest, "Prohibited characters");
   }   
}

How could I still validate the real exception class?

Upvotes: 4

Views: 2805

Answers (1)

Alex
Alex

Reputation: 5934

The main purpose of the WebTestClient is to test endpoints using fluent API to verify responses. There is no magic deserialization or error handling happening but you can get access to the raw responses (status, headers, body).

In your example you will not get MvcResult or ResponseStatusException but you could get access to the raw body using rsp.getResponseBody() that would look like

{
    "timestamp": "2022-05-17T17:57:07.041+00:00",
    "path": "/api",
    "status": 400,
    "error": "Bad Request",
    "requestId": "4fa648d"
}

You could use expectBody().consumeWith(rsp -> { ... }) to get access to the request and response or expectBody(String.class).value(body -> { ... }) to get just body. As an alternative use some fluent API to validate result JSON .expectBody().json(<expected json>) or .expectBody().jsonPath() to check specific fields only.

In addition you could still deserialize body explicitly using .expectBody(Response.class).value(body -> {...}).

Upvotes: 1

Related Questions