Search code examples
javaspringspring-bootintegration-testing

Using WebClient for Spring Boot integration testing


I'm trying to migrate some integration tests of a Spring Boot application from RestTemplate to WebClient. Currently, the tests use an autowired instance of TestRestTemplate

@Autowired
private TestRestTemplate restTemplate;

When the tests are run, restTemplate is configured to use the same base URL and (randomly chosen) port that the server runs on.

In one of my tests, I login and save the authorization response header value for use in subsequent API calls. I tried migrating this to WebClient like so

WebClient webClient = WebClient.create()

var authResult = webClient.post()
    .uri("/api/authenticate")
    .contentType(MediaType.APPLICATION_JSON)
    .bodyValue(new LoginDetails(username, password))
    .retrieve()
    .toBodilessEntity()
    .block();

// save the token that was issued and use it for subsequent requests
this.authHeader = authResult.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

But when I create the WebClient instance like this it is not configured to use the same port as the application.

I tried instead to use a dependency-injected instance of TestWebClient

@Autowired
private WebTestClient webTestClient;

This does connect the web client to the server (same base URL and port), however the WebTestClient API has quite a different API to WebClient. Specifically, it only seems to allow the properties of the response to be asserted, e.g. you can assert that a particular response header value exists, but there's no way to save that header's value.

var authResult = webTestClient.post()
    .uri("/api/authenticate")
    .contentType(MediaType.APPLICATION_JSON)
    .bodyValue(new LoginDetails(username, password))
    .exchange()
    .expectHeader()
    .exists(HttpHeaders.AUTHORIZATION);

Is there a way to either:

  • Create a WebClient instance that is configured to use the same base URL and port as the server
  • Create a WebTestClient instance and access the response properties (rather than just asserting them)

Solution

  • You can get full access to the WebTestClient result:

    webTestClient.post()
                    .uri("/api/authenticate")
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(new LoginDetails(username, password))
                    .exchange()
                    .expectHeader()
                    .exists(HttpHeaders.AUTHORIZATION)
                    .returnResult(Map.class);