Как тестировать REST API: стратегия проверок от контракта до негативных сценариев
Методика предполагает, что тестировщик умеет читать OpenAPI-схему и самостоятельно воспроизводить запросы. Если именно этого навыка пока не хватает, подборка курсов по API на KursHub показывает доступные программы в одном листинге. Их можно сопоставить по формату и продолжительности, а затем проверить, предусмотрена ли практика с контрактами, авторизацией и разбором ошибок: перечень инструментов сам по себе этого не гарантирует. Дальше учебная программа не понадобится — рабочий набор проверок можно собрать прямо по документации своего сервиса.
Три карты вместо одного чек-листа
Первая карта — контрактная. Спецификация OpenAPI Initiative описывает paths и operations, параметры, тело запроса, схему ответа, обязательные поля, ограничения значений и варианты ошибок. Но контракт отвечает только на вопрос «что обещано снаружи». Он не всегда показывает, какой ущерб причинит нарушение и что произошло с данными внутри системы.
Вторая карта описывает состояния ресурса. У заказа, например, могут быть состояния new, paid, shipped, cancelled. Важно не только получить 200 ОК, но и проверить допустимость перехода: оплаченный заказ можно передать в доставку, а уже отправленный, возможно, нельзя отменить. После операции следует заново прочитать ресурс и, если есть законный доступ, проверить связанное представление — список заказов, остаток товара, историю событий. Ответ endpoint и фактическое состояние иногда расходятся.
Третья карта — риск. Для планирования достаточно качественной оценки по трём вопросам:
насколько дорогим будет сбой для пользователя или бизнеса;
насколько вероятен этот сценарий;
насколько легко команда заметит ошибку без специальной проверки.
Это не универсальная математическая формула. Значения «высокий», «средний» и «низкий» нужны, чтобы провести обсуждение с разработчиком, аналитиком или владельцем продукта. Списание денег дважды обычно важнее лишнего необязательного поля в ответе, даже если вторую проверку написать проще.
Есть ещё слой, который нельзя вывести только из JSON Schema. Рабочая группа IETF в RFC 9110 задаёт семантику HTTP-методов: безопасные методы не должны запрашивать изменение состояния, а PUT, DELETE и безопасные методы определены как идемпотентные. Это не означает, что два ответа обязаны совпасть побайтно; ожидается одинаковый намеренный эффект на сервере. Поэтому повтор запроса — отдельная проверка, а не случайный дубль happy path.

Контракт, состояния и риск отвечают на разные вопросы, а вместе задают состав и очередность API-проверок.
Матрица, которая задаёт очередность тестов
Обычный чек-лист перечисляет «валидные данные», «невалидные данные», «авторизацию» и «производительность». В нём все строки выглядят равноценными. Рабочая матрица устроена иначе: она связывает обещание контракта с состоянием и последствиями.
Что фиксируем | Вопрос тестировщика | Пример для API заказов |
|---|---|---|
Пункт контракта | Какое внешнее обещание проверяем? | POST /orders принимает позиции и возвращает созданный заказ |
Состояние | Что было до запроса и что должно стать после? | заказа не было → создан один заказ в new |
Риск | Что случится при нарушении? | дубль заказа, неверная сумма, чужие данные |
Инвариант | Что обязано остаться истинным? | один клиентский ключ создаёт не более одного заказа |
Воздействие | Каким запросом нарушаем или подтверждаем условие? | повторяем POST после обрыва соединения |
Ожидаемый результат | Что увидит клиент и система? | тот же заказ либо определённая контрактом ошибка, без дубля |
Доказательство | Что приложить к дефекту? | оба запроса, ответы, время, correlation ID и повторный GET |
Приоритет | Почему тест идёт сейчас? | высокий: возможны двойное списание и ручная сверка |
Инвариант — центральная колонка. «Вернулся код 201» описывает один ответ, но не доказывает, что заказ создался ровно один раз, принадлежит нужному пользователю и содержит рассчитанную сервером сумму. Хороший инвариант переживает смену инструмента: его можно проверить в Postman, curl, автотесте или через диагностический клиент.
Доказательство тоже планируют до запуска. Если endpoint возвращает trace-id или correlation-id, его сохраняют вместе с методом, URL, заголовками, очищенным телом запроса, ответом и временем. Секреты и персональные данные перед передачей удаляют. Для операции, меняющей состояние, одного скриншота ответа мало: нужен контрольный запрос, показывающий состояние ресурса после действия.

Строка матрицы связывает обещание контракта, состояние, риск, инвариант и минимальный набор доказательств.
Учебный пример: заказ от создания до отмены
Рассмотрим условный сервис. Это не описание реального проекта: поля, коды и разрешённые переходы всегда берутся из документации конкретного API.
Пусть контракт содержит три операции:
POST /orders создать заказ
GET /orders/{orderId} получить заказ
POST /orders/{orderId}/cancel отменить заказ
У заказа есть состояния new, paid, shipped, cancelled. Клиент передаёт позиции и ключ идемпотентности, но итоговую сумму считает сервер.
Первый запрос — минимальный валидный заказ. Здесь проверяются не только статус и схема ответа. После POST нужно сделать GET, сопоставить владельца, позиции, серверную сумму и состояние new. Затем тот же запрос повторяют с тем же ключом. Инвариант: в системе остаётся один заказ. Как именно API сообщает о повторе — возвращает существующий ресурс или специальный ответ — определяет контракт; тест не должен навязывать сервису чужое поведение.
Следом полезнее проверить не пустую строку в необязательном комментарии, а чужой orderId. Проект OWASP в API Security Top 10 2023 относит нарушение авторизации на уровне объекта к основным рискам API: наличие доступа к самому endpoint ещё не означает право читать любой объект, идентификатор которого удалось подставить. Два пользователя создают по заказу, после чего каждый пытается прочитать и отменить чужой. Инвариант здесь сильнее конкретного кода: содержимое чужого заказа не раскрывается, его состояние не меняется.
Проверка переходов строится как маленький граф, а не как список методов. Отменить new допустимо — ресурс переходит в cancelled. Повторная отмена не должна неожиданно вернуть его в прежнее состояние или создать вторичное действие. Попытка отменить shipped получает предусмотренный контрактом отказ, а сам заказ остаётся shipped. Если внешне пришла ошибка, но переход всё же произошёл, это более опасный дефект, чем несовпадение текста сообщения.

Проверки API должны охватывать не только ответы, но и допустимые переходы, повтор операции и границы доступа к объекту.
После этих сценариев добавляют границы входных данных: нулевое количество, отсутствующий обязательный идентификатор товара, неизвестное поле, неверный тип, слишком длинное значение. Для каждого случая заранее решают, какой слой контракта нарушен. Иначе легко собрать десятки почти одинаковых тестов и всё равно пропустить двойное создание заказа или чужой доступ.
Примерная очередь получится такой:
Проверка | Риск | Инвариант | Минимальное доказательство |
|---|---|---|---|
Повтор создания с тем же ключом | высокий | создан не более чем один заказ | два POST, идентификаторы ответов, контрольный GET |
Чтение чужого заказа | высокий | данные владельца не раскрыты | два пользователя, запрос с чужим ID, очищенный ответ |
Отмена чужого заказа | высокий | состояние чужого ресурса не изменилось | запрос нарушителя и GET владельца после попытки |
Отмена отправленного заказа | высокий | shipped не переходит в cancelled | состояние до и после, ответ об ошибке |
Неверный тип поля | средний | ресурс не создан частично | тело запроса, problem details, поиск ресурса |
Неизвестное необязательное поле | зависит от контракта | поведение стабильно и документировано | запрос, ответ и ссылка на правило спецификации |
Так матрица не заменяет тест-дизайн. Она задаёт порядок, а уже внутри выбранной строки применяются классы эквивалентности, граничные значения, попарные комбинации или исследовательская проверка.
Негативный ответ — тоже часть контракта
Код 4xx ещё не делает отказ качественным. Клиенту нужно отличить невалидное поле от отсутствующего права, конфликт состояния — от временной недоступности. Рабочая группа IETF в RFC 9457 предлагает формат problem details для машиночитаемого описания ошибки. В типичном ответе могут быть type, title, status, detail и instance, а расширения способны указать проблемное поле. Конкретный набор остаётся частью контракта сервиса.
У негативного ответа проверяют несколько свойств одновременно:
код и тело не противоречат друг другу;
тип ошибки стабилен и пригоден для обработки клиентом;
ссылка на поле действительно указывает на ошибочный фрагмент;
локализуемый текст не меняет машинный идентификатор проблемы;
ответ не раскрывает stack trace, SQL, внутренние пути, токены и существование чужого объекта;
неуспешная операция не оставляет частично изменённое состояние.
Problem details не предназначен для передачи наружу всей отладочной информации. Подробности, необходимые разработчику, остаются в журнале и связываются с клиентским ответом через идентификатор. Поэтому тест отрицательного сценария заканчивается не чтением фразы «что-то пошло не так», а проверкой трёх мест: ответа, состояния ресурса и доступного диагностического следа.
Особое внимание требуется авторизации. OWASP отдельно различает права на объект, на его свойства и на функцию. Пользователь может законно читать свой заказ, но не видеть служебную маржу; менять адрес доставки, но не статус оплаты; вызывать обычную операцию, но не административную. Один тест «без токена получен 401» не покрывает эти границы.
Инструмент не определяет стратегию
Для ручной проверки достаточно клиента, который позволяет точно управлять методом, URL, заголовками и телом. Это может быть Postman, Insomnia, curl, встроенный HTTP-клиент IDE или небольшой скрипт. OpenAPI-интерфейс удобен для знакомства с контрактом, а вкладка Network — для восстановления реального клиентского сценария. Но перехваченный запрос ещё не является тестом: у него нет сформулированного инварианта и ожидаемого состояния.
Автоматизировать в первую очередь стоит устойчивое рискованное ядро: ключевые переходы состояния, права на объекты, повторы изменяющих операций, схемы важных ответов и воспроизводимые ошибки. Одноразовое исследование новой функции, визуальная оценка или ещё не стабилизированный контракт могут временно остаться ручными. Процент автоматизации здесь слабая цель; важнее, какие риски проверяются на каждом изменении.
Контрактный тест и end-to-end сценарий отвечают на разные вопросы. Первый быстро показывает, что поставщик или потребитель нарушил согласованную форму взаимодействия. Второй подтверждает, что реальный процесс проходит через несколько компонентов. Не стоит заставлять медленный сквозной тест доказывать каждую границу поля, а проверку схемы — подтверждать бизнес-переход, которого она не наблюдает.
Как собрать минимальный API-регресс
Если времени мало, начните не с максимального числа кейсов, а с пяти опорных проверок:
основной успешный сценарий с контрольным чтением итогового состояния;
самый дорогой недопустимый переход состояния;
чтение или изменение чужого объекта под легальным пользователем;
повтор изменяющего запроса после предполагаемого сетевого сбоя;
одна типовая ошибка валидации с проверкой машиночитаемого ответа и отсутствия частичного изменения.
Затем добавляйте границы данных, роли, редкие состояния, параллельные операции, ограничения ресурсов и нефункциональные проверки. Очередность может измениться: у публичного каталога риск чтения чужого объекта почти отсутствует, а у платёжного или медицинского API он определяет весь план.
Перед завершением тест-сессии полезно задать один вопрос: можно ли по собранным данным доказать не только неправильный ответ, но и нарушение обещания системы? Если в дефекте есть запрос, ожидаемый инвариант, состояние до и после, очищенный ответ и корреляционный идентификатор, разработчику не придётся угадывать, что именно сломалось. В этом и состоит практическая стратегия API-тестирования: не проверить всё подряд, а раньше обнаружить сбой с наибольшими последствиями и оставить достаточно следов, чтобы его исправили.