WebTestClient надає API-інтерфейс, ідентичний WebClient, аж до виконання запиту з exchange(). Приклади підготовки запиту з будь-яким вмістом, включано з даними форми, багатокомпонентними даними тощо, див. у документації WebClient.

Після виклику exchange() WebTestClient розходиться з WebClient і натомість продовжує робочий процес перевірки достовірності відповідей.

Щоб підтвердити статус відповіді та заголовки, використовуй таке:

Java

client.get().uri("/persons/1")
    .accept(MediaType.APPLICATION_JSON)
    .exchange()
    .expectStatus().isOk()
    .expectHeader().contentType(MediaType.APPLICATION_JSON);
Kotlin

client.get().uri("/persons/1")
    .accept(MediaType.APPLICATION_JSON)
    .exchange()
    .expectStatus().isOk()
    .expectHeader().contentType(MediaType.APPLICATION_JSON)

Якщо потрібно, щоб всі очікувані події були підтверджені, навіть якщо одна з них не спрацювала, то можна використовувати expectAll(..) замість кількох послідовних викликів expect*(..). Ця функція схожа на підтримку м'яких тверджень в AssertJ і assertAll() у JUnit Jupiter.

Java

client.get().uri("/persons/1")
    .accept(MediaType.APPLICATION_JSON)
    .exchange()
    .expectAll(
        spec -> spec.expectStatus().isOk(),
        spec -> spec.expectHeader().contentType(MediaType.APPLICATION_JSON)
);

Тому можна вибрати декодування тіла відповіді за допомогою одного з наступних способів:

  • expectBody(Class<T>): Декодуємо в один об'єкт.

  • expectBodyList(Class<T>) : Декодуємо і збираємо об'єкти в List<T>.

  • expectBody(): Декодуємо в byte[] для вмісту JSON або порожнього тіла.

І виконуємо затвердження на результуючому об'єкті більш високого рівня:

Java

client.get().uri("/persons")
        .exchange()
        .expectStatus().isOk()
        .expectBodyList(Person.class).hasSize(3).contains(person);
Kotlin

import org.springframework.test.web.reactive.server.expectBodyList
client.get().uri("/persons")
        .exchange()
        .expectStatus().isOk()
        .expectBodyList<Person>().hasSize(3).contains(person)

Якщо вбудованих тверджень недостатньо, можна використовувати замість цього об'єкта і виконати будь-які інші твердження:

Java

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)...
        });
Kotlin

client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk()
        .expectBody<Person>()
        .consumeWith {
            // спеціальні твердження (наприклад, AssertJ)...
        }

Або можна вийти з робочого процесу і отримати EntityExchangeResult:

Java

EntityExchangeResult<Person> result = client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk()
        .expectBody(Person.class)
        .returnResult();
Kotlin

import org.springframework.test.web.reactive.server.expectBody
val result = client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk
        .expectBody<Person>()
        .returnResult()
Якщо потрібно декодувати до цільового типу за допомогою узагальнень, шукай перевантажені методи, які приймають ParameterizedTypeReference замість Class<T>.

Відсутність вмісту

Якщо очікується, що у відповіді не буде вмісту, можна підтвердити це таким чином:

Java
 
client.post().uri("/persons")
        .body(personMono, Person.class)
        .exchange()
        .expectStatus().isCreated()
        .expectBody().isEmpty(); 
Kotlin

client.post().uri("/persons")
        .bodyValue(person)
        .exchange()
        .expectStatus().isCreated()
        .expectBody().isEmpty()

Якщо потрібно проігнорувати вміст відповіді, то нижче наведено вивільнення вмісту без будь-яких тверджень:

Java

client.get().uri("/persons/123")
        .exchange()
        .expectStatus().isNotFound()
        .expectBody(Void.class);
        
Kotlin

client.get().uri("/persons/123")
        .exchange()
        .expectStatus().isNotFound
        .expectBody<Unit>()

Вміст JSON

Можна використовувати expectBody() без цільового типу, щоб виконувати твердження для неформатованого вмісту, а не робити це через об'єкт(и) вищого рівня.

Щоб перевірити повний вміст JSON з допомогою JSONAssert:

Java

client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk()
        .expectBody()
        .json("{\"name\":\"Jane\"}")
Kotlin

client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk()
        .expectBody()
        .json("{\"name\":\"Jane\"}")

Щоб перевірити вміст JSON за допомогою JSONPath:

Java

client.get().uri("/persons")
        .exchange()
        .expectStatus().isOk()
        .expectBody()
        .jsonPath("$[0].name").isEqualTo("Jane")
        .jsonPath("$[1].name").isEqualTo("Jason");
Kotlin

client.get().uri("/persons")
        .exchange()
        .expectStatus().isOk()
        .expectBody()
        .jsonPath("$[0].name").isEqualTo("Jane")
        .jsonPath("$[1].name").isEqualTo("Jason")
        

Потокові відповіді

Щоб перевірити потенційно нескінченні потоки, такі як "text/event-stream" або "application/x-ndjson", почни з перевірки статусу та заголовків відповіді, а потім отримай FluxExchangeResult:

Java

FluxExchangeResult<MyEvent> result = client.get().uri("/events")
        .accept(TEXT_EVENT_STREAM)
        .exchange()
        .expectStatus().isOk()
        .returnResult(MyEvent.class);
Kotlin

import org.springframework.test.web.reactive.server.returnResult
val result = client.get().uri("/events")
        .accept(TEXT_EVENT_STREAM)
        .exchange()
        .expectStatus().isOk()
        .returnResult<MyEvent>()

Тепер ти готовий споживати потік відповідей за допомогою StepVerifier з reactor-test:

Java

Flux<Event> eventFlux = result.getResponseBody();
StepVerifier.create(eventFlux)
        .expectNext(person)
        .expectNextCount(4)
        .consumeNextWith(p -> ...)
        .thenCancel()
        .verify();
Kotlin

val eventFlux = result.getResponseBody()
StepVerifier.create(eventFlux)
        .expectNext(person)
        .expectNextCount(4)
        .consumeNextWith { p -> ... }
        .thenCancel()
            .verify()

Твердження MockMvc

WebTestClient — це HTTP-клієнт, тому він може перевіряти тільки те, що знаходиться у відповіді клієнта, включно зі статусом, заголовками та тілом. Для цього почни з отримання ExchangeResult після додавання затвердження до тіла:

Java

// Для відповіді з тілом
EntityExchangeResult<Person> result = client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk()
        .expectBody(Person.class)
        .returnResult();
// Для відповіді без тіла
EntityExchangeResult<Void> result = client.get().uri("/path")
        .exchange()
        .expectBody().isEmpty();
Kotlin

// Для відповіді з тілом
val result = client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk()
        .expectBody(Person.class)
        .returnResult();
// Для відповіді без тіла
val result = client.get().uri("/path")
        .exchange()
        .expectBody().isEmpty();

Потім перейди на затвердження відповіді сервера MockMvc:

Java

MockMvcWebTestClient.resultActionsFor(result)
        .andExpect(model().attribute("integer", 3))
        .andExpect(model().attribute("string", "a string value"));
Kotlin

MockMvcWebTestClient.resultActionsFor(result)
        .andExpect(model().attribute("integer", 3))
        .andExpect(model().attribute("string", "a string value"));