API-тесты основная масса автотестов в нормальной пирамиде: они в десятки раз быстрее UI, почти не флакают и проверяют бизнес-логику напрямую. Ручное тестирование API разбирается в треке «Тестирование API», здесь про то, как это автоматизировать.
Стек
- Python:
requestsилиhttpx+ pytest, схемы черезpydanticилиjsonschema. - Java: REST Assured (
given().when().then()) + JUnit 5 или TestNG. - JS/TS: фикстура
requestв Playwright,supertest,axios+ Vitest. - Postman-коллекции в CI запускают через Newman, но для большого набора код удобнее: ревью, переиспользование, типы.
Слои
tests/ сценарии и проверки
clients/ по клиенту на сервис: методы create_order(), get_order()
models/ схемы ответов (pydantic) и билдеры запросов
conftest.py базовый URL, авторизация, фабрики данных
Тест не должен собирать URL и заголовки руками. Он зовёт orders.create(...), а клиент знает путь, авторизацию и логирует запрос и ответ в отчёт.
Что проверять в ответе
- Статус: ровно ожидаемый (
201, а не «любой 2xx»). - Заголовки:
Content-Type,Locationу созданного ресурса, кеширование, CORS, если важно. - Тело: значения полей, которые важны сценарию.
- Схема: типы, обязательные поля, отсутствие лишнего. Ловит тихие изменения контракта.
- Побочный эффект: после
POSTсделатьGETи убедиться, что ресурс реально создан; послеDELETEполучить404. - Время ответа, если для эндпоинта есть требование.
def test_create_order(orders, user):
r = orders.create(user_id=user.id, items=[{"sku": "A1", "qty": 2}])
assert r.status_code == 201
order = Order.model_validate(r.json()) # pydantic: схема и типы
assert order.status == "new"
assert orders.get(order.id).json()["items"][0]["qty"] == 2
Негативные и граничные проверки
Без токена (401), с чужим токеном (403), несуществующий id (404), невалидное тело (400 или 422 с понятной ошибкой), граничные значения длины и чисел, повторный запрос. Хорошее правило: на каждый позитивный тест эндпоинта несколько негативных, их удобно параметризовать.
Идемпотентность
GET, PUT, DELETE по спецификации HTTP идемпотентны: повтор не меняет результат на сервере. POST нет. Для платежей часто вводят заголовок идемпотентности (Idempotence-Key в ЮKassa, Idempotency-Key у многих других): повтор с тем же ключом не создаёт второй платёж. Это обязательный тест для платёжного API.
Тестовые данные и изоляция
Каждый тест создаёт свои сущности через API и удаляет их в teardown фикстуры. Уникальность обеспечивают суффиксами (uuid4().hex[:8]), чтобы параллельный запуск не сталкивался. Поля вроде created_at и id в сравнениях игнорируют или проверяют по формату.
Контрактные тесты
В микросервисах важно, что потребитель и поставщик одинаково понимают API. Consumer-driven contracts (Pact): потребитель описывает ожидания в контракте, поставщик в своём CI проверяет, что им соответствует. Ломающее изменение видно до деплоя, без общего стенда. Альтернатива попроще: проверка ответов по OpenAPI-схеме.
Частые ошибки
- Проверять только статус
200. - Собирать запросы в тестах вручную, копируя заголовки.
- Зависеть от данных, созданных руками на стенде.
- Сравнивать весь ответ целиком вместе с
idи временем. - Не логировать запрос и ответ: упавший тест в CI невозможно разобрать.
Что спросят на собесе
- Что вы проверяете в ответе API, кроме статуса?
- Как устроен ваш API-фреймворк: клиенты, модели, фикстуры?
- Как проверяете схему ответа?
- Что такое идемпотентность и как её протестировать?
- Что такое контрактное тестирование?