Выбрать главу

ClassPathResource recentsResource =

   new ClassPathResource("/tacos/recent-tacos.json");

String recentsJson = StreamUtils.copyToString(

   recentsResource.getInputStream(), Charset.defaultCharset());

testClient.get().uri("/design/recent")

   .accept(MediaType.APPLICATION_JSON)

   .exchange()

   .expectStatus().isOk()

   .expectBody()

   .json(recentsJson);

Поскольку json() принимает String, вы должны сначала загрузить ресурс classpath в String. К счастью, Spring StreamUtils делает это играючи с copyToString(). String, возвращаемый функцией copyToString(), будет содержать весь JSON, который вы ожидаете получить в ответе на ваш запрос. Если передать его методу json(), контроллер получит правильный вывод.

Другой вариант, предлагаемый WebTestClient, позволяет сравнивать тело ответа со списком значений. МетодwellBodyList() принимает либо Class, либо ParameterizedTypeReference, указывающий тип элементов в списке, и возвращает объект ListBodySpec, для которого можно делать утверждения. Используя expectBodyList(), вы можете переписать тест, чтобы использовать подмножество тех же самых тестовых данных, которые вы использовали для создания моковского TacoRepository:

testClient.get().uri("/design/recent")

   .accept(MediaType.APPLICATION_JSON)

   .exchange()

   .expectStatus().isOk()

   .expectBodyList(Taco.class)

      .contains(Arrays.copyOf(tacos, 12));

Здесь вы утверждаете, что тело ответа содержит список, содержащий те же элементы, что и первые 12 элементов исходного массива Taco, созданного вами в начале тестового метода.

11.3.2 Тестирование POST-запросов

WebTestClient может делать больше, чем просто проверять GET запросы в контроллерах. Его также можно использовать для тестирования любого метода HTTP, включая запросы GET, POST, PUT, PATCH, DELETE и HEAD. Таблица 11.1 отображает методы HTTP на методы WebTestClient.

Таблица 11.1. WebTestClient тестирует любые запросы к контроллерам Spring WebFlux.

HTTP методы : WebTestClient метод

GET : .get()

POST : .post()

PUT : .put()

PATCH : .patch()

DELETE : .delete()

HEAD : .head()

В качестве примера тестирования еще один метод тестирования HTTP-запроса к контроллеру Spring WebFlux, давайте посмотрим на другой тест с DesignTacoController. На этот раз вы напишете тест конечной точки создания taco вашего API, отправив POST запрос в /design:

@Test

public void shouldSaveATaco() {

   TacoRepository tacoRepo = Mockito.mock(

   TacoRepository.class);                    //Устанавливает тестовые данные

   Mono<Taco> unsavedTacoMono = Mono.just(testTaco(null));

   Taco savedTaco = testTaco(null);

   savedTaco.setId(1L);

   Mono<Taco> savedTacoMono = Mono.just(savedTaco);

   when(tacoRepo.save(any())).thenReturn(savedTacoMono); //Mocks TacoRepository

   WebTestClient testClient = WebTestClient.bindToController(  //Создание WebTestClient

      new DesignTacoController(tacoRepo)).build();

   testClient.post()            //POST для тако

      .uri("/design")

      .contentType(MediaType.APPLICATION_JSON)

      .body(unsavedTacoMono, Taco.class)

      .exchange()

      .expectStatus().isCreated()            //Проверяет ответ

      .expectBody(Taco.class)

      .isEqualTo(savedTaco);

}

Как и в предыдущем методе тестирования, shouldSaveATaco начинается с настройки некоторых тестовых данных, моккинга TacoRepository, и создания WebTestClient, который привязан к контроллеру. Затем он использует WebTestClient для отправки POST запроса в /design с телом типа application/json и полезной нагрузкой, которая является JSON-сериализованной формой Taco в несохраненном Mono. После выполнения exchange() тест утверждает, что ответ имеет статус HTTP 201 (CREATED) и полезную нагрузку в теле, равную сохраненному объекту Taco.

11.3.3. Тестирование на живом сервере

Тесты, которые вы написали до сих пор, основывались на моковской реализации среды Spring WebFlux, так что реальный сервер не понадобился бы. Но вам может потребоваться протестировать контроллер WebFlux в контексте сервера, такого как Netty или Tomcat, и, возможно, с хранилищем или другими зависимостями. То есть вы должны быть способны написать интеграционный тест.

Чтобы написать интеграционный тест WebTestClient, начните с аннотирования класса теста с помощью @RunWith и @SpringBootTest, как и любого другого интеграционного теста Spring Boot:

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

public class DesignTacoControllerWebTest {

   @Autowired

   private WebTestClient testClient;

}

Установив для атрибута webEnvironment значение WebEnvironment.RANDOM_PORT, вы просите Spring запустить работающий сервер, прослушивающий случайным образом выбранный порт (Вы могли бы также установить для webEnvironment значение WebEnvironment.DEFINED_PORT и указать порт с атрибутом properties, но это обычно нежелательно. Это открывает риск столкновения портов с работающим сервером).

Вы, думаю, заметите, что вы также автоматически подключили WebTestClient к тестовому классу. Это означает не только то, что вам больше не нужно создавать его в своих методах тестирования, но и то, что вам не нужно указывать полный URL-адрес при отправке запросов. Это потому, что WebTestClient будет настроен, чтобы узнать, на каком порту работает тестовый сервер. Теперь вы можете переписать shouldReturnRecentTacos() в качестве интеграционного теста, в котором используется автоматическая привязка WebTestClient: