WebTestClient
provides an API identical to WebClient, up to the execution of
the request with using exchange()
. For examples of preparing a request with any content, including form
data, multipart data, and more, see the documentation for WebClient.
After exchange()
is called, WebTestClient
diverges from WebClient
and instead
continues the response validation workflow .
To confirm response status and headers, use the following:
client.get().uri("/persons/1")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON);
client.get().uri("/persons/1")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON)
If you want all expected events to be acknowledged, even if one of them fails, you can use
expectAll(..)
instead of several consecutive calls to expect*(..)
. This feature is similar
to soft assertions support in AssertJ and assertAll()
in JUnit Jupiter.
client.get().uri("/persons/1")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectAll(
spec -> spec.expectStatus().isOk(),
spec -> spec.expectHeader().contentType(MediaType.APPLICATION_JSON)
);
You can then choose to decode the response body using one of the following methods:
expectBody(Class<T>)
: Decoding into one object.expectBodyList(Class<T>)
: Decoding and collecting objects intoList<T>
.expectBody()
: Decoding intobyte[]
for JSON content or an empty body.
And execute assertions on the resulting higher-level object(s):
client.get().uri("/persons")
.exchange()
.expectStatus().isOk()
.expectBodyList(Person.class).hasSize(3).contains(person);
import org.springframework.test.web.reactive.server.expectBodyList
client.get().uri("/persons")
.exchange()
.expectStatus().isOk()
.expectBodyList<Person>().hasSize(3).contains(person)
If the built-in assertions are not enough, you can use them instead this object and execute any other statements:
import org.springframework.test.web.reactive.server.expectBody
client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody(Person.class)
.consumeWith(result -> {
// special statements (eg AssertJ)...
});
client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody<Person>()
.consumeWith {
// special statements (eg AssertJ)...
}
Or you can exit the workflow and get EntityExchangeResult
:
EntityExchangeResult<Person> result = client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody(Person.class)
.returnResult();
import org.springframework.test.web.reactive.server.expectBody
val result = client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk
.expectBody<Person>()
.returnResult()
ParameterizedTypeReference
instead of Class<T>
.
No content
If the response is expected to have no content, then you can confirm this as follows:
client.post().uri("/persons")
.body(personMono, Person.class)
.exchange()
.expectStatus().isCreated()
.expectBody().isEmpty();
client.post().uri("/persons")
.bodyValue(person)
.exchange()
.expectStatus().isCreated()
.expectBody().isEmpty()
If you want to ignore the contents of the response, then below is the release of the contents without any assertions :
client.get().uri("/persons/123")
.exchange()
.expectStatus().isNotFound()
.expectBody(Void.class);
client.get().uri("/persons/123")
.exchange()
.expectStatus().isNotFound
.expectBody<Unit>()
JSON content
You can use expectBody()
without a target type to make
assertions on unformatted content, rather than having to do it through the higher-level object(s).
To examine the full JSON content with using JSONAssert:
client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody()
.json("{\"name\":\"Jane\"}")
client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody()
.json("{\"name\":\"Jane\"}")
To check the content JSON using JSONPath:
client.get().uri("/persons")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$[0].name").isEqualTo("Jane")
.jsonPath("$[1].name").isEqualTo("Jason");
client.get().uri("/persons")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$[0].name").isEqualTo("Jane")
.jsonPath("$[1].name").isEqualTo("Jason")
Stream responses
To check for potentially infinite streams , such as "text/event-stream"
or "application/x-ndjson"
, start by checking the response status and headers, and then get FluxExchangeResult
:
FluxExchangeResult<MyEvent> result = client.get().uri("/events")
.accept(TEXT_EVENT_STREAM)
.exchange()
.expectStatus().isOk()
.returnResult(MyEvent.class);
import org.springframework.test.web.reactive.server.returnResult
val result = client.get().uri("/events")
.accept(TEXT_EVENT_STREAM)
.exchange()
.expectStatus().isOk()
.returnResult<MyEvent>()
You are now ready to consume the response stream using StepVerifier
from
reactor-test
:
Flux<Event> eventFlux = result.getResponseBody();
StepVerifier.create(eventFlux)
.expectNext(person)
.expectNextCount(4)
.consumeNextWith(p -> ...)
.thenCancel()
.verify();
val eventFlux = result.getResponseBody()
StepVerifier.create(eventFlux)
.expectNext(person)
.expectNextCount(4)
.consumeNextWith { p -> ... }
.thenCancel()
.verify()
MockMvc Assertions
WebTestClient
is HTTP client, so it can only check what's in the
client response, including status, headers, and body.
When testing a Spring MVC application with a MockMvc
server setup, you have the additional ability to perform further assertions on the server response .To do this,
start by getting the ExchangeResult
after adding the assertion to the body:
// For a response with body
EntityExchangeResult<Person> result = client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody(Person.class)
.returnResult();
// For a response without a body
EntityExchangeResult<Void> result = client.get().uri("/path")
.exchange()
.expectBody().isEmpty();
// For a response with a body
val result = client.get().uri("/persons/1")
.exchange()
.expectStatus().isOk()
.expectBody(Person.class)
.returnResult();
// For a response without a body
val result = client.get().uri("/path")
.exchange()
.expectBody().isEmpty();
Then switch to MockMvc server response assertions:
MockMvcWebTestClient.resultActionsFor(result)
.andExpect(model().attribute("integer", 3))
.andExpect(model().attribute("string", "a string value"));
MockMvcWebTestClient.resultActionsFor(result)
.andExpect(model().attribute("integer", 3))
.andExpect(model().attribute("string", "a string value"));
GO TO FULL VERSION