Тестирование API в Postman
Кнопка на странице — лишь витрина. Настоящие данные ходят по HTTP, и тестировать их можно (и нужно) отдельно от интерфейса.
API (Application Programming Interface) — способ, которым одна программа обращается к другой. В веб-разработке это чаще всего HTTP-запросы к серверу: браузер просит данные, сервер отвечает JSON. Postman — инструмент, который позволяет отправлять такие запросы вручную, складывать их в коллекции и автоматически проверять ответы.
Зачем тестировать API отдельно от интерфейса
Новичку кажется, что если кнопка работает — значит, работает всё. На самом деле интерфейс — это тонкий слой поверх API, и тестирование только через него оставляет огромные слепые зоны.
- Раньше. Backend обычно готов на неделю-две раньше фронтенда. Ждать интерфейс, чтобы начать тестировать, — значит терять эти недели и потом чинить всё в спешке.
- Глубже. Через форму нельзя отправить возраст
-5: браузер не даст. А злоумышленник или сломанный клиент — отправит. Валидацию на сервере можно проверить только напрямую через API. - Стабильнее. UI-тесты падают от переехавшей кнопки. API-тесты падают, только когда действительно сломался контракт.
- Точнее в диагностике. Когда UI-тест красный, непонятно, кто виноват. Когда красный API-тест, виноват сервер — и это уже половина расследования.
Именно поэтому в пирамиде тестирования API-уровень стоит посередине: он дешевле и быстрее, чем UI, и покрывает бизнес-логику, до которой юнит-тесты не дотягиваются.
Анатомия HTTP-запроса
Любой запрос состоит из четырёх частей: метод, URL (с query-параметрами), заголовки и тело.
POST https://api.shop.dev/v1/orders?notify=true
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...
{ "product_id": 42, "quantity": 2 }
Методы описывают намерение. Их путают постоянно, поэтому запомните таблицу:
| Метод | Что делает | Меняет данные? | Идемпотентен? |
GET | Получить данные | Нет | Да |
POST | Создать новую сущность | Да | Нет |
PUT | Заменить сущность целиком | Да | Да |
PATCH | Изменить часть полей | Да | Обычно да |
DELETE | Удалить | Да | Да |
Идемпотентность — повторный одинаковый запрос не меняет результат. Два одинаковых PUT оставят ресурс в том же состоянии, а два одинаковых POST создадут два заказа. Отсюда классический баг: пользователь дважды нажал «Оплатить» — и списалось дважды. Проверять двойную отправку — обязательный пункт чек-листа.
Коды ответов: язык, на котором сервер говорит с вами
Первая цифра кода задаёт класс: 2xx — успех, 3xx — перенаправление, 4xx — ошибка клиента (вы прислали что-то не то), 5xx — ошибка сервера (сломался он). Уже одно это делит баги пополам.
| Код | Значение | Что проверять тестировщику |
200 OK | Успех | Что в теле действительно те данные: 200 с пустым или неверным телом — тоже баг |
201 Created | Сущность создана | Должен вернуться id созданного объекта (часто ещё заголовок Location) |
204 No Content | Успех, тела нет | Типичный ответ на DELETE. Тело обязано быть пустым |
400 Bad Request | Запрос невалиден | Битый JSON, отсутствует обязательное поле |
401 Unauthorized | Вы не представились | Нет токена или он протух |
403 Forbidden | Вы представились, но вам нельзя | Права доступа. Золотая жила багов: обычный пользователь редактирует чужой заказ |
404 Not Found | Ресурса нет | Отличайте «нет объекта» от «неверный URL» |
409 Conflict | Конфликт состояния | Повторная регистрация того же email |
422 Unprocessable Entity | JSON понят, но данные бессмысленны | Возраст -5, дата в прошлом |
429 Too Many Requests | Слишком часто | Rate limit — проверяйте, что он вообще есть |
500 Internal Server Error | Сервер упал | Всегда баг. Даже на самый дикий ввод сервер обязан ответить 400/422, а не 500 |
Разница 401 и 403 — любимый вопрос на собеседовании. Мнемоника: 401 — «я тебя не знаю», 403 — «я тебя знаю, и тебе нельзя».
Коллекции, окружения и переменные
Один запрос в Postman — это уже полезно. Но реальная сила начинается, когда вы собираете коллекцию: папку запросов, которая описывает целый сценарий («регистрация → логин → создание заказа → отмена заказа»). Коллекцию можно передать коллеге, положить в git и запустить целиком.
Чтобы одна и та же коллекция работала и на тестовом стенде, и на препроде, адреса и токены не пишут в запросах напрямую. Их выносят в переменные, а наборы переменных — в окружения (environments).
Окружение "stage" Окружение "dev"
baseUrl = https://api.stage.shop.dev baseUrl = http://localhost:8000
userEmail = qa@shop.dev userEmail = qa@shop.dev
token = (заполняется скриптом) token = (заполняется скриптом)
Запрос в коллекции: GET {{baseUrl}}/v1/orders/{{orderId}}
Переключили окружение в выпадашке — вся коллекция поехала на другой стенд, ни один запрос править не пришлось. Уровни переменных, от узкого к широкому: local (внутри одного прогона) → environment → collection → global. При совпадении имён побеждает более узкий.
Важное правило безопасности: боевые токены и пароли не место в коллекции, которую вы коммитите в репозиторий. Для них в Postman есть тип переменной secret, а в CI — переменные окружения.
Проверки: вкладка Tests
Глазами сверять ответы можно ровно до пятого запроса. Дальше нужны автоматические проверки. В Postman они пишутся на JavaScript во вкладке Scripts → Post-response (в старых версиях — Tests) и выполняются сразу после получения ответа.
// 1. Статус-код
pm.test("Статус 201", function () {
pm.response.to.have.status(201);
});
// 2. Время ответа
pm.test("Отвечает быстрее 800 мс", function () {
pm.expect(pm.response.responseTime).to.be.below(800);
});
// 3. Содержимое тела
pm.test("Заказ создан с нужным количеством", function () {
const body = pm.response.json();
pm.expect(body).to.have.property("id");
pm.expect(body.quantity).to.eql(2);
pm.expect(body.status).to.eql("created");
});
// 4. Сохраняем id для следующих запросов коллекции
const body = pm.response.json();
pm.environment.set("orderId", body.id);
Результат в панели Test Results:
PASS Статус 201
PASS Отвечает быстрее 800 мс
PASS Заказ создан с нужным количеством
Последняя строка примера — самая интересная. pm.environment.set кладёт id только что созданного заказа в переменную, и следующий запрос коллекции сможет обратиться к {{orderId}}. Так из отдельных запросов собирается сквозной сценарий: залогинились → сохранили токен → создали заказ → сохранили id → отменили заказ по этому id.
Зеркальный механизм — Pre-request-скрипт: он выполняется до отправки и удобен, чтобы сгенерировать уникальный email или посчитать текущую дату.
Как это работает
Postman — это, по сути, обычный HTTP-клиент с приятным интерфейсом. Когда вы жмёте Send, происходит следующее:
- Подставляются переменные:
{{baseUrl}}заменяется на строку из активного окружения. - Выполняется pre-request-скрипт (если есть) в изолированной JS-песочнице.
- Формируется и отправляется настоящий HTTP-запрос — точно такой же, какой послал бы браузер или мобильное приложение.
- Приходит ответ; запускается post-response-скрипт, и его
pm.test(...)дают зелёные или красные строки.
Отсюда важное следствие: Postman не «эмулирует» приложение, он говорит с сервером на том же языке. Если запрос из Postman отработал, а из браузера — нет, значит, дело не в сервере, а в том, что именно шлёт фронтенд. Это первый шаг к разделению багов фронта и бэка, о котором пойдёт речь в следующем уроке.
Коллекцию целиком гоняет Collection Runner, а в CI ту же коллекцию запускает консольная утилита Newman — так ручные проверки бесплатно превращаются в автотесты на каждый коммит.
Частые ошибки
- Проверять только статус-код.
200 OKс телом{"orders": []}, когда заказы есть, — зелёный тест и настоящий баг. Всегда проверяйте содержимое. - Тестировать только happy path. Ценность API-тестирования — в негативных кейсах: пустое тело, лишние поля, чужой id, строка вместо числа, гигантский текст, отсутствующий токен.
- Хардкод токена в запросе. Через сутки он протухнет, и вся коллекция покраснеет. Получайте токен первым запросом и кладите в переменную.
- Тесты, зависящие от порядка и данных. Кейс, который проходит только на «свежей» базе или только если запущен третьим, будет мигать в CI и обесценит весь набор. Создавайте нужные данные внутри сценария и удаляйте за собой.
- Забыть
Content-Type: application/json. Сервер получит тело, но не поймёт формат и ответит400или415— и вы полдня будете искать баг там, где его нет. - Не отличать
5xxот4xx.400на кривой ввод — правильное поведение, это не баг.500на кривой ввод — баг всегда. - Гонять коллекцию по проду. Особенно
POSTиDELETE. Сначала проверьте, какое окружение выбрано в выпадающем списке, — это дисциплина, которая однажды спасёт вам карьеру.
Итоги
- API-тестирование начинается раньше UI, достаёт до серверной валидации и точнее указывает на виновника.
- Метод описывает намерение; помните про идемпотентность: два
POST= две сущности. - Код ответа — первая развилка:
4xx— виноват клиент,5xx— всегда баг сервера.401≠403. - Коллекция + окружения + переменные
{{baseUrl}},{{token}}= один набор запросов на все стенды. - Вкладка Tests превращает ручные проверки в автоматические: статус, время, тело, сохранение данных для следующего шага.
- Проверяйте не только счастливый путь: негативные кейсы — главная ценность уровня API.