REST Assured

Что делает REST Assured сильным выбором для API automation в Java-стеке и на что стоит смотреть в архитектуре тестов.

Обновлено:

Содержание

REST Assured — Java-библиотека для HTTP-проверок с выразительным DSL. Она позволяет описывать запрос и проверять статус, заголовки и тело ответа. Обычно её используют вместе с JUnit Jupiter или другим runner, который управляет кейсами, подготовкой и итоговым результатом запуска.

Инструмент полезен в Java-команде: тесты могут использовать привычную сборку, типы данных и инфраструктуру. Но удобная цепочка given–when–then не определяет качество проверки. Для QA важны бизнес-ожидания, реальные границы интеграции и управляемое состояние системы.

Зависимости и выбранная версия

Пример рассчитан на Maven-проект с JDK 17+, зависимостью io.rest-assured:rest-assured:6.2.0 в test scope и настроенным запуском JUnit Jupiter. Документация REST Assured указывает эту версию на дату подготовки статьи. Версию runner и плагина сборки закрепите в проекте по их требованиям.

Не объявляйте автоматически любой новый релиз совместимым с существующим набором. Перед обновлением смотрят release notes, транзитивные зависимости и изменение API. Для учебного примера нужен стандартный модуль JDK jdk.httpserver; он создаёт локальный сервер без внешнего приложения.

Самостоятельная проверка HTTP-ответа

Сохраните класс как src/test/java/OrderApiTest.java и запустите mvn -Dtest=OrderApiTest test в подготовленном Maven-проекте. Сервер выбирает свободный порт и отвечает синтетическим заказом. Никакие реальные сервисы, базы или credentials не используются.

java
import com.sun.net.httpserver.HttpServer;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;

class OrderApiTest {
  @Test
  void readsDraftOrder() throws Exception {
    var server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
    server.createContext("/orders/42", exchange -> {
      byte[] body = "{\"id\":42,\"status\":\"draft\"}"
          .getBytes(StandardCharsets.UTF_8);
      exchange.getResponseHeaders().set("Content-Type", "application/json");
      exchange.sendResponseHeaders(200, body.length);
      try (var output = exchange.getResponseBody()) {
        output.write(body);
      }
    });
    server.start();
    try {
      given().baseUri("http://127.0.0.1")
          .port(server.getAddress().getPort())
      .when().get("/orders/42")
      .then().statusCode(200)
          .contentType("application/json")
          .body("id", equalTo(42))
          .body("status", equalTo("draft"));
    } finally {
      server.stop(0);
    }
  }
}

Ожидается один успешный кейс. Изменение ожидаемого статуса заказа на paid должно дать содержательное падение проверки тела. Пример показывает технику HTTP-assertions; он не доказывает работу сервиса заказов, поскольку ответ намеренно сформирован локальным fixture.

Что означает цепочка DSL

given задаёт параметры запроса: URL, headers, тело и аутентификацию. when выполняет действие. then проверяет полученный ответ. Такая структура помогает видеть предусловия и результат, но не должна превращаться в длинную цепь несвязанных проверок.

Разделяйте обязательный контракт и важные бизнес-поля. Проверить весь JSON дословно бывает слишком хрупко, если ответ содержит время и технические метаданные. Но проверять только наличие поля тоже слабо: заказ с чужим ownerId останется незамеченным.

Подготовка данных и реальные операции

В тестовом сервисе создайте отдельную корзину с двумя товарами по 5 000 денежных единиц. Примените согласованный купон десять процентов. Ожидайте итог 9 000, идентификатор своей корзины и корректное сохранённое состояние после повторного чтения.

Негативный кейс отправляет неизвестный купон и проверяет предусмотренный код ошибки, причину и неизменную сумму. Статусы и округление берут из контракта продукта. Случайное ожидание «любая ошибка 4xx» пропустит подмену валидации ошибкой доступа.

Проверку владения выполняйте отдельными клиентами двух ролей. Владелец читает созданный заказ, другой пользователь обращается к тому же ID и получает предусмотренный отказ без чужих данных. Следующая операция первого пользователя должна по-прежнему работать. Такое чередование помогает увидеть случайное смешивание credentials или серверного контекста. Очистка использует точный идентификатор и права владельца тестовых данных, а не общий запрос удаления всех заказов. Для параллельного запуска сохраняйте связь каждого ресурса с конкретным прогоном и проверяйте результат подготовки до начала основного assertion.

RequestSpecification и повторение

RequestSpecification помогает собрать общие настройки: базовый адрес, тип содержимого, безопасные headers и фильтры. Храните в ней техническую конфигурацию, а данные конкретного сценария передавайте явно. Это уменьшает повторение, сохраняя читабельность запроса.

Изменяемая глобальная конфигурация усложняет понимание параллельного выполнения и смены ролей. Даже если конкретная версия улучшает потокобезопасность внутренних механизмов, общие credentials или объекты данных всё равно способны смешать сценарии. Предпочитайте явную локальную спецификацию и изолированные сущности.

JSON Schema и смысл данных

Проверка схемы помогает контролировать обязательность и типы полей. Для неё используется отдельный модуль json-schema-validator и схема поддерживаемого выбранной версией формата. Проверяйте возможности версии, прежде чем копировать схему из другого проекта.

Схема не подтверждает корректную стоимость, доступ к ресурсу или переход статуса. Комбинируйте структурные assertions с конкретными бизнес-ожиданиями. При работе с десятичными значениями учитывайте представление чисел и используйте подходящий тип или matcher, а не случайное сравнение float.

Наблюдение асинхронного результата

Принятый HTTP-запрос может только поставить задачу в очередь. Если контракт обещает отложенный результат, проверка должна наблюдать его через согласованную границу: статус операции, событие или повторное чтение. Ожидание ограничивают временем и сохраняют последний ответ для диагностики.

Не отправляйте создание заказа заново в каждом цикле ожидания. Повторяют безопасное наблюдение уже созданной операции. Идемпотентность запроса проверяют отдельным сценарием с предусмотренным механизмом, а не предполагают на основании используемого HTTP-метода.

Логи и расследование

Полезный отказ показывает метод, безопасный адрес, ожидаемое и фактическое поле, код ответа и идентификатор операции. Логирование только при ошибке уменьшает шум, но фильтры должны исключать токены, cookie и чувствительные payload.

Если сервер отвечает HTML вместо JSON, сначала исследуют маршрут, redirect, proxy и авторизацию. Ошибка парсинга является симптомом. Нельзя автоматически лечить её изменением JSON-пути или разрешением любого content type: это может скрыть настоящий дефект интеграции.

Ошибки и рабочие выводы

Частые проблемы: сравнение только status 200, общий заказ на весь набор, скрытая смена ролей и предположение, что успешная десериализация равна корректному ответу. Не отключайте TLS-проверку для любого окружения: сначала установите причину проблемы сертификата и согласованный тестовый trust store.

REST Assured даёт удобный язык HTTP-проверок. Надёжность появляется из ясного контракта, независимых данных и проверки последствий. Начните с небольшого воспроизводимого сценария и расширяйте набор по рискам сервиса, сохраняя понятные причины каждого assertion.

При добавлении кейса укажите, какой новый риск он контролирует: ещё один успешный запрос не обязательно расширяет полезное покрытие сервиса.

Что ещё почитать