Раздел 09 — Тестирование API вручную

Проверить сервер напрямую — без интерфейса, который прячет и ограничивает запросы

Прогресс курса Раздел 9 из 12

Что вы освоите в этом разделе

8 академических часов: 2 теории, 6 практики. Нужны curl (в Windows 10 и 11 уже есть) и Bruno — бесплатная программа для запросов к API, работает без учётной записи. Примеры сняты в Windows 11: curl 8.21, Bruno 4.3.
01

Зачем тестировать API

API (application programming interface) — способ, которым программы обращаются к серверу без человека: мобильное приложение, сайт на JavaScript, другие сервисы. У «Задачника» есть и веб-интерфейс, и JSON API по адресам /api/….

Через API тестировщик проверяет сервер напрямую. Интерфейс ограничивает запросы: не даёт ввести приоритет 0, не показывает кнопку запрещённого перехода, не позволяет отправить поле другого типа. API этих ограничений не имеет — и злоумышленник тоже пользуется им напрямую. Поэтому проверки API находят дефекты, которые через интерфейс не видны вовсе, а проверка в разделе 08 «обойти клиентскую проверку» здесь становится обычным запросом.

02

HTTP: запрос и ответ

Каждое обращение к API — пара «запрос — ответ»:

POST /api/login HTTP/1.1                  ← метод, адрес, версия протокола
Host: 127.0.0.1:8000                       ← заголовки
Content-Type: application/json

{"login": "ivan", "password": "Ivan2026pass"}   ← тело

HTTP/1.0 200 OK                            ← код состояния
Content-Type: application/json; charset=utf-8

{"token": "…"}                             ← тело ответа
МетодЧто делаетПример
GETПолучить, ничего не меняяGET /api/tasks — список задач
POSTСоздать или выполнить действиеPOST /api/tasks — новая задача
PATCHИзменить часть полейPATCH /api/tasks/5 — новое название
PUTЗаменить целикомв «Задачнике» нет
DELETEУдалитьDELETE /api/tasks/5

Стиль, где адрес называет объект (/api/tasks/5 — задача 5), а метод — действие с ним, называют REST. Ответы обычно в JSON: объекты {"ключ": значение}, массивы […], строки в двойных кавычках, числа, true/false, null.

Код состояния — первое, что проверяют:

КодЗначитКогда
200 OKУспешноПолучили, изменили
201 CreatedСозданоПосле POST, создавшего объект
204 No ContentУспешно, тела нетУдалили, вышли
400 Bad RequestОшибка в запросеНеверное поле, неверный JSON
401 UnauthorizedНе авторизованНет токена или он недействителен
403 ForbiddenАвторизован, но нельзяЧужой объект, нет прав
404 Not FoundНет такогоНеверный адрес или id
409 ConflictПротиворечит состояниюЗапрещённый переход статуса, дубликат
500 Internal Server ErrorСервер упалВсегда дефект: сервер должен был ответить 4xx

Коды 4xx — «виноват клиент», и это нормальный ответ на негативную проверку. Код 5xx — «виноват сервер»: необработанная ошибка, которую нужно исправлять.

03

Документация OpenAPI

OpenAPI (раньше Swagger) — стандартный формат описания API: адреса, методы, поля запроса, коды и поля ответов. Для тестировщика это требования к API (Т8.1). Описание «Задачника» — http://127.0.0.1:8000/api/openapi.json; откройте в браузере — Edge и Chrome покажут его с отступами. Начало файла:

{
  "openapi": "3.1.0",
  "info": {
    "title": "Задачник API",
    "version": "1.0"
  },
  "servers": [
    {
      "url": "http://127.0.0.1:8000"
    }
  ],
  "components": {

Что выписать из документации для проверок:

Bruno умеет импортировать OpenAPI и сразу создать коллекцию со всеми адресами. В этом разделе мы собираем коллекцию вручную — так лучше видно, что проверяется.

04

curl: запросы из командной строки

curl есть в Windows 10 и 11 и почти в любом Linux. Основные ключи: -i — показать код и заголовки ответа, -X — метод, -H — заголовок, --json — отправить JSON (сам ставит Content-Type).

Две ловушки Windows PowerShell. 1) curl в PowerShell 5.1 — не curl, а другая команда (Invoke-WebRequest); пишите curl.exe. 2) JSON в кавычках прямо в команде PowerShell 5.1 передаёт программе без внутренних кавычек, и сервер получает сломанное тело — в «Задачнике» это видно как ошибка сервера. Надёжный способ — положить JSON в файл и отправлять --json "@файл.json". В cmd и Linux такой проблемы нет.

Запрос без токена (PowerShell, Windows 11):

PS C:\tasker> curl.exe -i http://127.0.0.1:8000/api/tasks
HTTP/1.0 401 Unauthorized
Server: Tasker
Date: Thu, 29 Oct 2026 10:07:53 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 99

{
  "error": "Требуется вход: заголовок Authorization: Bearer <токен>"
}

Вход: создайте в папке «Задачника» файл login.json (Блокнот, кодировка UTF-8) с текстом {"login": "ivan", "password": "Ivan2026pass"} и отправьте его:

PS C:\tasker> curl.exe --json "@login.json" http://127.0.0.1:8000/api/login
{
  "token": "38e22c9c78a9fd5ed9e5cf6a51da6a01"
}

Токен у вас будет другой. Сохраните его в переменной и передавайте в заголовке Authorization:

PS C:\tasker> $token = "38e22c9c78a9fd5ed9e5cf6a51da6a01"
PS C:\tasker> curl.exe -H "Authorization: Bearer $token" "http://127.0.0.1:8000/api/tasks?status=in_progress"
[
  {
    "id": 1,
    "title": "Подготовить отчёт за квартал",
    "due": "2026-10-27",
    "priority": 1,
    "status": "in_progress",
    "overdue": true,
    "created": "2026-10-29 13:07:50",
    "updated": "2026-10-29 13:07:50"
  },
  …
]

Несуществующая задача — 404 и ошибка в JSON:

PS C:\tasker> curl.exe -i -H "Authorization: Bearer $token" http://127.0.0.1:8000/api/tasks/9999
HTTP/1.0 404 Not Found
Server: Tasker
Date: Thu, 29 Oct 2026 10:07:54 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 49

{
  "error": "Задача не найдена"
}

Те же запросы в Linux (bash) — JSON можно писать прямо в команде, в одинарных кавычках:

curl -i http://127.0.0.1:8000/api/tasks
curl --json '{"login": "ivan", "password": "Ivan2026pass"}' http://127.0.0.1:8000/api/login
TOKEN=38e22c9c78a9fd5ed9e5cf6a51da6a01
curl -H "Authorization: Bearer $TOKEN" 'http://127.0.0.1:8000/api/tasks?status=in_progress'
curl -X PATCH -H "Authorization: Bearer $TOKEN" --json '{"title": "Новое"}' http://127.0.0.1:8000/api/tasks/3

Если curl старый и отвечает, что не знает ключ --json: -H "Content-Type: application/json" -d "@login.json". Кириллица в ответах в окне терминала Windows 11 показывается правильно; если передать вывод curl дальше командам PowerShell (| ConvertFrom-Json, > файл), буквы могут исказиться — сохраняйте ответ ключом -o ответ.json.

05

Bruno: коллекция запросов

curl удобен для одного запроса, а для набора проверок, которые нужно повторять, удобнее Bruno. Он хранит коллекцию файлами в папке на диске — её можно положить в git и отдать одногруппнику. Учётная запись не нужна. Postman делает то же, но требует учётную запись и хранит коллекции в облаке.

Как собрать коллекцию «Задачника»:

  1. Create Collection — имя и папка на диске.
  2. Окружение: в правом верхнем углу «No Environment» → Configure → создать local с переменной base = http://127.0.0.1:8000. Адреса запросов пишутся как {{base}}/api/login — для другого сервера достаточно другого окружения.
  3. Запрос входа: метод POST, адрес {{base}}/api/login, вкладка Body → JSON, тело с логином и паролем. Отправить — кнопка Send или Ctrl+Enter.
  4. Токен в переменную: вкладка Vars → Post Response, переменная token со значением res.body.token. Теперь после входа токен запоминается сам.
  5. Авторизация в остальных запросах: вкладка Auth → Bearer Token, значение {{token}}.
Bruno 4.3: слева коллекция «Задачник» с запросами POST Вход и GET Задачи в работе; запрос POST {{base}}/api/login, тело JSON с логином ivan и паролем; справа ответ 200 OK с полем token; окружение local выбрано справа вверху

Слева — коллекция, в середине — запрос (метод, адрес, тело), справа — ответ с кодом, временем и размером. Второй запрос — список задач в работе — берёт токен из переменной:

Bruno: запрос GET {{base}}/api/tasks?status=in_progress, на вкладке Params параметр status = in_progress; ответ 200 OK — массив из двух задач со статусом in_progress и полями id, title, due, priority, overdue, created, updated
06

Проверки в Bruno

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

test("200 и только задачи в работе", function () {
  expect(res.getStatus()).to.equal(200);
  res.getBody().forEach(t => expect(t.status).to.equal("in_progress"));
});

После отправки результат — на вкладке Tests ответа (может прятаться под »): зелёная галочка — проверка прошла, красный крестик — нет, с объяснением «expected 200 to equal 201».

Bruno: вкладка Tests ответа — Tests (1), Passed: 1, Failed: 0, зелёная галочка у проверки «200 и только задачи в работе»
Что проверитьСтрока в test(…)
Код ответаexpect(res.getStatus()).to.equal(201);
Поле ответаexpect(res.getBody().priority).to.equal(2);
Поле есть и это строкаexpect(res.getBody().error).to.be.a("string");
Длина спискаexpect(res.getBody()).to.have.lengthOf(8);
Заголовокexpect(res.getHeader("content-type")).to.contain("application/json");

Запуск всей коллекции: правой кнопкой по коллекции → Run. Bruno пройдёт запросы по порядку и покажет, какие проверки не прошли, — это уже почти регрессионный набор API, и в курсе автоматизации его запускают без интерфейса.

07

Какие проверки придумать

Техники разделов 05–06 работают и для API — только вместо полей формы поля JSON. Для каждого адреса:

ГруппаПроверкиОжидается
ПозитивныеКаждый метод из OpenAPI с корректными данными; поля ответа совпадают с отправленнымиКод из документации, поля по схеме
Обязательные поляПоле пропущено; null; пустая строка400 и понятная ошибка
ТипыЧисло строкой "3", строка вместо числа, true, массив, объект400
ГраницыТе же, что в разделе 05: длины, диапазоны, датыКак в требованиях
ЛишнееНеизвестное поле "owner": "maria", "id": 1Игнорируется или 400, но не меняет данные
ФорматСломанный JSON {title:; пустое тело; другой Content-Type400, не 500
СостоянияЗапрещённые переходы из таблицы раздела 06, которых нет в интерфейсе409
Адрес и методНесуществующий id; id строкой /api/tasks/abc; неподдерживаемый метод404, 405
АвторизацияБез токена; неверный токен; токен после выхода401 на каждом адресе, где он нужен
Чужие данныеТокен одного пользователя, id объекта другого404 или 403; данные не показаны и не изменены

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

08

Доступ к чужим данным

Один из самых частых и опасных дефектов API: сервер проверяет, что пользователь вошёл, но не проверяет, что объект — его. Подставив в адрес чужой номер, пользователь видит или меняет чужие данные. В классификации OWASP это первое место списка API Security Top 10 (BOLA — broken object level authorization).

Как проверять в учебном приложении:

  1. Войти под первым пользователем, получить токен A; под вторым — токен B.
  2. С токеном B получить список своих задач и выписать id.
  3. С токеном A отправить GET, PATCH, DELETE и смену статуса для id задачи второго пользователя.
  4. Ожидается 404 (или 403) на каждый запрос; затем с токеном B убедиться, что задача не изменилась.
Только своё. Подбор чужих id на чужом сайте без разрешения владельца — неправомерный доступ к компьютерной информации (ст. 272 УК РФ), даже если «просто посмотрели». Эти проверки — для «Задачника» на своём компьютере и для проектов, которые вы тестируете по заданию владельца.
09

Баг-репорт об API

Для дефекта API шаги — это запрос. В баг-репорт вставляют команду curl целиком (без настоящих паролей рабочих систем) или команду, которую Bruno собирает сам (значок </> справа от адреса запроса, вариант curl), фактический ответ с кодом и ожидаемый — со ссылкой на OpenAPI:

API: GET /api/orders/{id} с id несуществующего заказа отвечает 500 вместо 404

Окружение: «Магазин» 2.3 API, test.example.ru; curl 8.21
Требование: OpenAPI, /api/orders/{id} → responses 404
Шаги:
  curl.exe -i -H "Authorization: Bearer <токен test01>" https://test.example.ru/api/orders/999999
Фактический результат: HTTP 500, тело «Internal Server Error» (не JSON)
Ожидаемый результат: HTTP 404, {"error": "…"}

Ключевые выводы раздела

Запомните главное

  • API проверяет сервер без ограничений интерфейса — там находятся дефекты, невидимые в браузере
  • 4xx — правильный отказ на негативную проверку, 5xx — всегда дефект
  • OpenAPI — требования к API: адреса, поля, коды; расхождение с ним — баг-репорт
  • В Windows PowerShell — curl.exe и JSON из файла --json "@файл.json"
  • Bruno: окружение с {{base}}, токен в переменной, проверки на вкладке Tests, запуск всей коллекции
  • Авторизацию проверяют на каждом адресе, а чужие данные — токеном одного пользователя и id другого
Практические задания — на учебном портале. Задания, критерии оценивания, сдача работ и оценки преподавателя — в курсе на portal.nevabit.ru. Учётную запись выдаёт преподаватель.
Раздел 08: Тестирование веб-интерфейса Все разделы Раздел 10: Данные и журналы