Тестирование API: как проверять REST-сервисы вручную и что автоматизировать

Тестирование API: как проверять REST-сервисы вручную и что автоматизировать

Коротко:

  • API-тестирование проверяет не интерфейс, а логику: контракт между сервисами, корректность данных и поведение при ошибках.
  • Начинать стоит с ручной проверки в Postman или Insomnia - это быстро показывает, что вообще происходит на уровне запросов.
  • Чаще всего баги прячутся не в happy path, а в граничных значениях, неверных токенах и нестандартных комбинациях параметров.
  • Автоматизировать имеет смысл регрессию и контрактные проверки, а не разовые исследовательские сценарии.
  • Статус-код 200 не означает, что всё хорошо: тело ответа может содержать ошибку, пустой массив или чужие данные.

Зачем тестировать API отдельно от UI

Когда команда тестирует только через интерфейс, она видит продукт глазами пользователя - но не видит, что происходит между сервисами. Интерфейс может скрывать ошибки: показывать «Заказ оформлен», хотя бэкенд вернул 500, или молча игнорировать пустой ответ. Проблема всплывает позже - в логах, в жалобах поддержки, в инциденте.

Тестирование на уровне API позволяет проверить логику напрямую, без прослойки UI. Это быстрее, точнее и дешевле в поддержке. Кроме того, многие продукты вообще не имеют собственного интерфейса: они предоставляют эндпоинты для мобильных приложений, партнёрских систем или внутренних сервисов.

Для тестировщика понимание HTTP-уровня - это не «дополнительный навык», а базовая часть профессии. Без него сложно объяснить разработчику, где именно сломалось, и невозможно написать осмысленный баг-репорт на интеграционную проблему.

Что именно проверяется при тестировании REST API

REST-сервис отвечает на HTTP-запросы и возвращает данные - чаще всего в формате JSON. Тестировщик проверяет несколько уровней сразу.

Статус-коды

Сервер сообщает о результате через трёхзначный код. 2xx - успех, 4xx - ошибка на стороне клиента, 5xx - проблема на сервере. Но важно не просто получить нужный код, а убедиться, что он соответствует ситуации.

КодЧто означаетТипичная ошибка
200 OKЗапрос выполненТело содержит ошибку или пустые данные
201 CreatedРесурс созданНет Location-заголовка с адресом нового объекта
400 Bad RequestНеверный запросНет описания, какое именно поле некорректно
401 UnauthorizedНет авторизацииВозвращается вместо 403, хотя токен есть
404 Not FoundРесурс не найденВозвращается при удалённом объекте вместо 410
500 Internal Server ErrorОшибка сервераСтек трейс попадает в тело ответа

Тело ответа

Структура JSON должна соответствовать документации или контракту. Проверяют: наличие обязательных полей, типы данных, форматы дат и идентификаторов, отсутствие лишних данных (например, паролей или внутренних флагов).

Заголовки

Content-Type должен совпадать с реальным содержимым. Если сервер говорит application/json, а возвращает HTML с ошибкой - это баг. Также проверяют заголовки кэширования, CORS, авторизационные токены в ответе.

Время ответа

Не нагрузочное тестирование, а базовый контроль: эндпоинт не должен отвечать 8 секунд там, где ожидается 200 мс. Аномальное время часто указывает на проблему с запросом к базе или внешней зависимостью.

Как устроен ручной процесс проверки

Большинство тестировщиков начинают с Postman - он бесплатен, не требует настройки и позволяет быстро отправить первый запрос. Альтернатива - Insomnia, более лёгкая и без обязательной авторизации в облаке.

Базовый сценарий проверки нового эндпоинта выглядит так:

  1. Прочитать документацию или спецификацию (Swagger, OpenAPI, Confluence).
  2. Собрать запрос: метод, URL, заголовки, тело.
  3. Отправить happy path - корректные данные, ожидаемый результат.
  4. Проверить статус-код, структуру ответа, типы полей.
  5. Проверить граничные значения и негативные сценарии.
  6. Зафиксировать результат: что ожидалось, что пришло, в чём расхождение.

Важно не останавливаться на шаге 3. Happy path почти всегда работает - его проверяют разработчики ещё до коммита. Ценность тестировщика в том, что он идёт дальше.

Негативные сценарии: где прячутся реальные баги

Большинство дефектов в API живут не в основном сценарии, а на его краях. Вот что стоит проверять систематически.

Авторизация и права доступа

  • Запрос без токена - должен вернуть 401, а не данные.
  • Просроченный токен - должен вернуть 401, а не 500.
  • Токен другого пользователя - нельзя получить чужие данные (IDOR-уязвимость).
  • Токен с недостаточными правами - должен вернуть 403, а не 200 с пустым ответом.

Некорректные данные в теле запроса

  • Пустое обязательное поле.
  • Поле с неверным типом (строка вместо числа).
  • Отрицательное или нулевое значение там, где ожидается положительное.
  • Очень длинная строка (проверка на SQL-инъекцию и переполнение).
  • Специальные символы: кавычки, угловые скобки, эмодзи.

Параметры в URL

  • Несуществующий ID ресурса.
  • ID в неверном формате (строка вместо UUID).
  • Отрицательные значения в пагинации (page=-1, limit=0).
  • Очень большое значение limit (попытка выгрузить всю базу).

Состояние ресурса

  • Повторный запрос на создание того же объекта - идемпотентность.
  • Удаление уже удалённого ресурса.
  • Обновление объекта в финальном статусе (например, закрытый заказ).

Частая ошибка: считать, что если сервер вернул 400, значит всё нормально. Важно проверить, что в теле ответа есть понятное сообщение об ошибке с указанием конкретного поля. Ответ {"error": "invalid input"} без деталей - это тоже баг, просто другого рода.

Работа с документацией и контрактом

Хорошая точка отсчёта для тестирования - OpenAPI-спецификация (Swagger). Она описывает эндпоинты, параметры, схемы запросов и ответов. Если спецификация есть, тестировщик может:

  • Сравнить реальный ответ с описанной схемой.
  • Найти поля, которые есть в ответе, но не задокументированы.
  • Найти поля из документации, которые не приходят в ответе.
  • Проверить, что типы данных совпадают.

Если спецификации нет - это само по себе риск. В таком случае тестировщик фиксирует фактическое поведение как базовую линию и договаривается с командой, что считать корректным.

Расхождение между документацией и реальным поведением - это баг, даже если сервис «работает». Клиент, который пишет интеграцию по документации, получит сюрприз в продакшне.

Инструменты: что выбрать и для чего

ИнструментДля чего подходитКогда выбирать
PostmanРучная проверка, коллекции, базовые скриптыСтарт, командная работа, документирование запросов
InsomniaРучная проверка без облакаКогда не нужна синхронизация и хочется простоты
curlБыстрая проверка из терминалаОтладка на сервере, скрипты, CI-среда
REST-assuredАвтотесты на JavaПроект на Java, нужна интеграция с JUnit/TestNG
pytest + requestsАвтотесты на PythonГибкость, быстрый старт, смешанные проекты
NewmanЗапуск Postman-коллекций в CIУже есть коллекции в Postman, нужна автоматизация

Postman - разумный выбор для начала. Но важно понимать его ограничения: сложные сценарии с динамическими данными, параллельным запуском и версионированием удобнее реализовывать в коде.

Что автоматизировать, а что оставить руками

Автоматизация API-тестов окупается быстрее, чем UI-автоматизация: запросы стабильнее, нет проблем с рендерингом, скорость выполнения выше. Но это не значит, что нужно автоматизировать всё подряд.

Хорошие кандидаты для автоматизации:

  • Регрессионные проверки - то, что нужно запускать при каждом деплое.
  • Контрактные тесты - проверка, что схема ответа не изменилась.
  • Smoke-тесты - базовая доступность ключевых эндпоинтов.
  • Проверки авторизации - стандартные сценарии с токенами.

Что лучше оставить в ручном режиме или исследовательском тестировании:

  • Новый эндпоинт, который ещё меняется - автотест придётся переписывать каждый день.
  • Сложные бизнес-сценарии с нестандартными данными - их сначала нужно понять.
  • Проверки, которые нужны один раз для конкретного релиза.

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

Аутентификация и сессии: отдельный слой проверок

Большинство реальных API требуют авторизации. Тестировщику важно понимать, как она устроена, чтобы правильно собирать запросы и находить уязвимости.

Основные схемы:

  • Bearer-токен (JWT) - передаётся в заголовке Authorization. Проверяют: срок жизни, поведение при истечении, возможность использовать токен после logout.
  • API Key - статический ключ в заголовке или параметре. Проверяют: что происходит при неверном ключе, есть ли ограничения по IP или rate limiting.
  • OAuth 2.0 - сложнее, но принцип тот же: нужно проверить все переходы между состояниями токена.
  • Basic Auth - логин и пароль в заголовке. Встречается в старых или внутренних сервисах.

Отдельная тема - проверка прав доступа между ролями. Если в системе есть admin и user, тестировщик должен убедиться, что user не может вызвать admin-эндпоинты, даже если знает их URL.

Типичные ошибки при тестировании API

Некоторые из них делают даже опытные специалисты.

Считать 200 успехом без проверки тела. Сервер может вернуть 200 с {"success": false, "error": "not found"}. Это нарушение контракта, но тест «прошёл».

Не проверять идемпотентность POST-запросов. Если пользователь дважды нажал «Оформить заказ», должен создаться один заказ или два? Ответ зависит от требований, но поведение нужно проверить явно.

Игнорировать пагинацию. Эндпоинт возвращает первые 20 записей корректно, но при запросе страницы 999 падает с 500 - это баг.

Не проверять поведение при недоступной зависимости. Если внешний сервис не отвечает, API должен вернуть понятную ошибку, а не зависнуть на 30 секунд.

Тестировать только в одной среде. Конфигурация dev и staging может отличаться. Баг, который воспроизводится только в prod, часто связан с разными настройками окружения.

Чеклист для проверки REST-эндпоинта

  • Happy path: корректный запрос возвращает ожидаемый статус и структуру.
  • Тело ответа: все обязательные поля присутствуют, типы данных верные.
  • Запрос без авторизации возвращает 401.
  • Запрос с чужим токеном не возвращает чужие данные.
  • Запрос с недостаточными правами возвращает 403.
  • Обязательные поля в теле: проверены пустые и отсутствующие значения.
  • Граничные значения числовых параметров проверены.
  • Несуществующий ID возвращает 404 с понятным сообщением.
  • Повторный запрос на создание обрабатывается корректно.
  • Время ответа в пределах разумного для данного эндпоинта.
  • Content-Type в ответе соответствует реальному содержимому.
  • Реальное поведение совпадает с документацией или спецификацией.

Версионирование и обратная совместимость

Когда API развивается, команды добавляют новые версии: /v1/orders, /v2/orders. Тестировщику важно понимать, что это создаёт отдельный слой проверок.

Во-первых, старая версия должна продолжать работать после выхода новой. Клиенты, которые интегрировались по /v1, не должны получить сюрприз в виде изменённой схемы или удалённых полей. Это называется обратной совместимостью, и её нарушение - один из самых болезненных багов в публичных сервисах.

Во-вторых, нужно проверять поведение при запросе к устаревшей версии. Хорошая практика - возвращать заголовок Deprecation с датой отключения. Плохая практика - молча удалить эндпоинт и ждать, пока клиенты начнут жаловаться.

Что проверять при работе с версиями:

  • Запрос к /v1 после выхода /v2 возвращает корректный ответ, а не 404.
  • Поля, которые были в /v1, присутствуют в /v2 или задокументировано их отсутствие.
  • Запрос к несуществующей версии (/v99) возвращает понятную ошибку.
  • Если версия объявлена устаревшей, в ответе есть соответствующий заголовок.

Часто эту область вообще не тестируют, потому что «старое работало раньше». Именно поэтому регрессия по предыдущим версиям особенно важна при каждом крупном релизе.

Rate limiting и поведение под нагрузкой

Большинство публичных и внутренних сервисов ограничивают количество запросов в единицу времени. Это защита от злоупотреблений и случайных петель в коде. Тестировщику важно проверить не только то, что ограничение существует, но и то, как именно оно работает.

Пример сценария: мобильное приложение при открытии делает 5 параллельных запросов к одному эндпоинту. Если rate limit настроен на 3 запроса в секунду, часть из них получит 429 Too Many Requests. Интерфейс показывает пустой экран без объяснений. Пользователь думает, что приложение сломалось. Это баг не в лимите, а в обработке ответа 429 на клиенте.

Что стоит проверить в рамках ручного и автоматизированного тестирования:

  • При превышении лимита сервер возвращает 429, а не 500 или 200 с ошибкой в теле.
  • В ответе есть заголовок Retry-After, который указывает, когда можно повторить запрос.
  • После сброса окна лимита запросы снова проходят корректно.
  • Разные роли или тарифы имеют разные лимиты, и они применяются правильно.

Это пограничная область между функциональным и нагрузочным тестированием. Полноценную нагрузку проверяют отдельными инструментами, но базовое поведение при превышении лимита - это обычная функциональная проверка, которую можно сделать вручную.

Как читать и использовать логи при отладке

Когда запрос ведёт себя неожиданно, тестировщик смотрит не только на ответ, но и на логи сервера. Это не всегда доступно, но когда доступно - сильно ускоряет диагностику.

Полезные источники информации при отладке:

  • Серверные логи: показывают, что именно получил сервер, как обработал и почему вернул тот или иной ответ.
  • Заголовок X-Request-ID или аналогичный: позволяет найти конкретный запрос в логах по идентификатору.
  • Время обработки в заголовках ответа: некоторые сервисы возвращают X-Response-Time, что помогает понять, где именно возникает задержка.
  • Трейсинг в распределённых системах: если сервис вызывает другие сервисы, инструменты вроде Jaeger или Zipkin показывают полную цепочку вызовов.

Тестировщику не обязательно уметь читать все форматы логов на уровне DevOps-инженера. Но базовое понимание - найти нужный запрос, прочитать сообщение об ошибке, передать разработчику конкретный trace ID - это навык, который заметно повышает качество баг-репортов и скорость их исправления.

Сравнение подходов к организации проверок

На практике команды используют разные модели организации работы с проверками на уровне сервисов. Каждая подходит для своего контекста.

ПодходКогда подходитПлюсыМинусы
Ручные коллекции в PostmanНебольшая команда, частые измененияБыстро обновлять, легко шаритьНет версионирования, сложно масштабировать
Автотесты в коде (pytest, REST-assured)Стабильный продукт, есть CI/CDВерсионирование, параллельный запускТребует поддержки, нужен навык кодирования
Контрактные тесты (Pact)Микросервисы, несколько командЛовит breaking changes до деплояСложная настройка, нужна культура в команде
Генерация тестов из OpenAPIЕсть актуальная спецификацияБыстрый старт, покрытие схемыНе покрывает бизнес-логику и edge cases

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

FAQ

Что такое API-тестирование простыми словами?

Это проверка того, как сервер обрабатывает запросы и что возвращает в ответ. Тестировщик отправляет HTTP-запросы напрямую, без интерфейса, и проверяет статус-коды, структуру данных и поведение при ошибках.

Чем API-тестирование отличается от UI-тестирования?

UI-тестирование проверяет то, что видит пользователь в браузере или приложении. Проверка на уровне API работает с сырыми запросами и ответами - быстрее, стабильнее и ближе к логике системы. Многие баги видны только на этом уровне.

Нужно ли знать программирование для тестирования API?

Для ручной проверки в Postman - нет. Для написания автотестов - да, хотя бы базовый Python или JavaScript. Знание программирования расширяет возможности, но не является обязательным условием для старта.

Что такое IDOR и почему это важно проверять?

IDOR (Insecure Direct Object Reference) - уязвимость, при которой пользователь может получить доступ к чужим данным, просто изменив ID в запросе. Например, /orders/123 возвращает заказ другого пользователя. Это критичный баг безопасности, который часто пропускают при функциональном тестировании.

Как проверить API без документации?

Начните с перехвата трафика через браузерные инструменты разработчика или Charles Proxy - так можно увидеть реальные запросы, которые делает интерфейс. Зафиксируйте структуру запросов и ответов как базовую линию и договоритесь с командой, что считать корректным поведением.

Когда API-тесты стоит добавить в CI/CD?

Когда есть стабильный набор проверок, которые нужно запускать при каждом деплое. Обычно это smoke-тесты и регрессия по ключевым эндпоинтам. Нестабильные или часто меняющиеся тесты в пайплайн добавлять не стоит - они будут создавать ложные срабатывания.

Что такое контрактное тестирование и зачем оно нужно?

Контрактное тестирование проверяет, что формат данных между двумя сервисами не изменился. Если один сервис переименовал поле, другой об этом узнает не в продакшне, а на этапе CI. Инструменты - Pact, Spring Cloud Contract. Подробнее об этом подходе - в отдельной статье про contract testing.

Итог

Тестирование API - это не отдельная специализация, а обязательная часть работы любого QA-инженера, который работает с современными продуктами. Понимание HTTP, умение читать JSON и находить расхождения с контрактом - это базовый уровень, без которого сложно объяснить разработчику, где именно сломалось.

Начинать стоит с ручной проверки в Postman: собрать коллекцию для своего проекта, пройти негативные сценарии, научиться читать заголовки и тело ответа. Автоматизация придёт позже - когда понятно, что именно нужно проверять регулярно и что достаточно стабильно, чтобы тест не падал каждую неделю из-за изменений.

Главное - не останавливаться на статус-коде 200. Реальные баги живут глубже.