API-тестування: об'єкт перевірки, рівні й інструменти
Зміст
Половина того, що робить застосунок, ніколи не показується на екрані. Кнопка «Оформити замовлення» — це лише обгортка над запитом, який летить на сервер, змінює баланс, списує товар зі складу, надсилає лист і повертає відповідь. UI показує вам щасливий кінець («Дякуємо за замовлення!»), але не показує, що в тілі відповіді ціна прийшла від'ємна, що замовлення створилося двічі або що чужий користувач може прочитати ваш чек, підмінивши один номер у запиті. Усе це живе на рівні API — і саме тому API-тестування перевіряє логіку там, де вона насправді працює.
Ця глава — карта розділу. Ми розберемо, що таке API-тестування і чим воно відрізняється від тестування через інтерфейс, де воно стоїть у піраміді тестів, що саме на цьому рівні перевіряють, які бувають типи API і чим їх ганяти — від однорядкового curl до автотестів у коді. Далі кожна тема отримає власну главу; тут — фундамент, на який вони спираються.
Що означає «тестувати API»
API (application programming interface) — це контракт, за яким одна програма звертається до іншої. У вебі це майже завжди HTTP-запит на певний URL з певним методом і тілом, у відповідь на який сервер повертає , заголовки й тіло (зазвичай JSON). Якщо клієнт-серверна модель і формати даних для вас ще туман — почніть із глав «Клієнт-сервер і як працює веб» та «REST API та формати даних»; тут ми на них спираємось.
Тестувати API означає слати запити безпосередньо до цього інтерфейсу й перевіряти відповідь — не відкриваючи браузер і не клікаючи кнопок. Замість «заповнити форму й натиснути Save» ви надсилаєте POST /api/orders з готовим JSON-тілом і перевіряєте, що прийшов статус 201, у тілі є id створеного замовлення, а сам запис справді з'явився. Ви працюєте з системою мовою, якою розмовляють її власні компоненти.
Ключова ідея вже на цій діаграмі: UI-тест проходить увесь стек — браузер, верстку, JavaScript, мережу, бекенд, базу. API-тест заходить збоку, одразу в бекенд, оминаючи весь фронтенд. Тому він швидший, стабільніший і бачить те, чого не видно з екрана.
Чим API-тести відрізняються від тестування через UI
«Чому» тут важливіше за «як». UI-тест відповідає на питання «чи може користувач зробити X через інтерфейс?» — і платить за це повнотою стека: він повільний, бо чекає рендеринг і анімації, і крихкий, бо ламається від зміни верстки, яка ніяк не стосується логіки. API-тест відповідає на інше питання — «чи правильно поводиться бізнес-логіка й дані?» — і за рахунок вужчого зрізу отримує швидкість і стабільність.
| Аспект | Через UI | Через API |
|---|---|---|
| Що перевіряє | Увесь стек очима користувача | Логіку й дані бекенду |
| Швидкість | Секунди на тест | Десятки–сотні мілісекунд |
| Стабільність | Ламається від зміни верстки | Ламається від зміни контракту, а не верстки |
| Що видно | Тільки те, що показує UI | Статус, усі поля тіла, заголовки |
| Підготовка даних | Довга, через кроки в UI | Швидка, одним запитом |
З таблиці не варто робити висновок «API краще за UI». Вони відповідають на різні питання. Кнопка може бути прив'язана до неправильного , поле — не відправлятися, помилка з API — не показуватися користувачу: усе це ловить лише UI-тест. Тому це не заміна, а розподіл праці — і його формалізує піраміда.
Місце в піраміді тестування
— орієнтир, що показує, скільки тестів варто мати на кожному рівні. Знизу — багато дешевих і швидких модульних (unit) тестів; посередині — інтеграційні та API-тести; згори — мало повільних наскрізних (E2E) тестів через UI.
API-рівень — та сама золота середина. Він на порядок швидший і стабільніший за E2E, але, на відміну від unit-тестів, ганяє систему зібраною: справжній сервер, справжня база, справжня серіалізація. Одним API-тестом ви покриваєте цілий бізнес-сценарій, який через UI тягнув би десяток крихких кроків. Тому типова порада — переносити перевірки якнайнижче: усе, що можна перевірити на рівні API, не варто перевіряти через браузер. Детальний розбір рівнів, вартості й антипатернів (як-от «пісочний годинник» чи «ріжок морозива») — у розділі «Автоматизація»; тут достатньо запам'ятати, що API-тести — робоча конячка більшості команд.
Що саме перевіряємо на рівні API
Об'єкт перевірки на рівні API — п'ять речей. Кожній далі присвячена окрема глава, тут — короткий орієнтир.
- Функціональність — чи правильно ендпоінт робить свою роботу: створює, читає, оновлює, видаляє потрібний ресурс, рахує суму, застосовує знижку. Це серце тест-дизайну для API — «Тест-дизайн для API: CRUD, параметри, межі».
- Дані — форма і зміст відповіді: правильні типи полів, немає зайвого, дати в очікуваному форматі, числа не округлені криво. Це тема глави «Перевірки відповіді: статус, тіло, заголовки, схема».
- Контракт — чи відповідає API домовленості між командами: ті самі поля, ті самі статуси, зворотна сумісність зі старими клієнтами. Про це — «OpenAPI/Swagger: специфікація як джерело істини» і «Контрактне тестування і сумісність версій».
- Помилки — як система поводиться, коли все йде не так: невалідний JSON, відсутнє обов'язкове поле, неправильний тип, конфлікт. Правильний код і зрозуміле тіло помилки — «Негативні перевірки й обробка помилок».
- Доступи — хто що може: чи віддає ендпоінт
401без токена,403чужому користувачу, чи не можна дістатися чужих даних перебором id. Це «Авторизація в API: ролі, доступи, негативні сценарії»; механіка самих токенів — у «Автентифікація та авторизація».
Типи API оглядово
«API» — не один протокол. На співбесіді корисно розрізняти хоча б п'ять і розуміти, чим тестування кожного відрізняється.
| Тип | Транспорт і формат | Що характерно для тестування |
|---|---|---|
| REST | HTTP + JSON | Ресурси й методи (GET/POST/PUT/DELETE), статус-коди несуть сенс |
| SOAP | XML поверх HTTP | Суворий контракт (WSDL), громіздкі конверти, живе в enterprise/легасі |
| GraphQL | HTTP + JSON, один ендпоінт | Клієнт сам описує запит; у легасі-режимі статус не є оракулом, помилки — в масиві errors |
| gRPC | RPC, за замовчуванням protobuf | Бінарний формат, у браузері не подивишся як JSON, потрібен grpcurl/код |
| Вебхуки | Вихідний HTTP-запит | Це сервер стукає до вас; треба приймач, а не запит |
REST — найпоширеніший стиль: система як набір ресурсів, доступних за URL, з методами HTTP і осмисленими статус-кодами. Йому присвячена більшість цього розділу. SOAP старіший і формальніший — обмін XML-конвертами за строгим описом WSDL; ви зустрінете його переважно в банках і телекомі. GraphQL перевертає підхід: один ендпоінт, а клієнт запитом описує, які саме поля хоче; це породжує власні пастки, розібрані в «GraphQL: особливості тестування». gRPC — бінарний і швидкий, для зв'язку між сервісами; його разом із SOAP і чергами розбирає «SOAP, gRPC і асинхронні API».
Окремо стоять вебхуки (webhooks): тут напрям зворотний — не ви шлете запит, а зовнішня система сама надсилає HTTP-запит на ваш URL, коли стається подія (оплата пройшла, лист доставлено). Щоб їх перевірити, потрібен не клієнт, а ; стратегія — у «Мокання залежностей: стаби, mock-сервери, вебхуки». Реалтайм-канали на кшталт WebSocket — ще один окремий світ, описаний у веб-главі «WebSockets і реалтайм».
Інструментарій: від curl до коду
Інструменти вишиковуються в природну сходинку — від найшвидшого разового пострілу до повноцінної автоматизації.
curl — HTTP-клієнт, який є майже на кожній машині. Ідеальний, щоб швидко перевірити один запит або вкласти точну команду відтворення в баг-репорт:
curl -i -X POST https://api.example.com/orders \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"productId": 42, "qty": 2}'
-i покаже статус і заголовки відповіді — те, що на рівні API часто важливіше за тіло.
Postman — найпопулярніший графічний клієнт: колекції запитів, змінні оточення, вбудовані скрипти-перевірки, спільна робота команди. З нього зручно починати ручне дослідження API; йому присвячені «Postman: основи» і глава про скрипти й Newman. Insomnia — легший клієнт із тією ж ідеєю. Bruno — молодший конкурент, який зберігає колекції звичайними файлами прямо в репозиторії, тож їх видно в git поряд із кодом; це зручно для рев'ю й версіонування.
Верхня сходинка — код. Коли перевірок стають десятки, вони мають ганятися в CI на кожен і сплітатися в ланцюжки (створити → прочитати → видалити), графічний клієнт стає тісним. Тоді запити пишуть у тестовому фреймворку. У Playwright для цього є вбудований APIRequestContext:
test('створення замовлення повертає 201 і id', async ({ request }) => {
const response = await request.post('/api/orders', {
data: { productId: 42, qty: 2 },
});
expect(response.status()).toBe(201);
const body = await response.json();
expect(body.id).toBeTruthy();
});
Той самий запит, що й у curl, але вже з перевіркою, повторюваний і придатний для CI. Як будувати такі тести, клієнти й ланцюжки — у «API-автотести в коді: клієнти, структура, ланцюжки». А підглянути реальні запити застосунку, перш ніж відтворювати їх у тесті, найзручніше через вкладку Network у DevTools.
Ручне vs автоматизація
Ручне API-тестування (через Postman чи curl) незамінне, коли ви вивчаєте незнайомий API, робите дослідницьку перевірку гіпотези, відтворюєте баг або ганяєте одноразовий сценарій. Тут швидкість зворотного зв'язку важливіша за повторюваність.
Автоматизація виправдана там, де перевірки треба повторювати часто й однаково: , ланцюжки CRUD, запуск на кожен коміт у CI, перевірка десятків комбінацій параметрів. API-рівень — узагалі найвдячніший кандидат на автоматизацію: тести швидкі, стабільні й не залежать від верстки. На практиці ці два режими не конкурують — руками досліджують і формулюють перевірку, а те, що варто стерегти постійно, переносять у код. Чому API-тести все одно бувають нестабільними й що з цим робити — у «Стабільність API-тестів: флак, асинхронність, дебаг».
Баги, які видно лише на рівні API
Це головний аргумент, чому QA спускається під UI. Ціла категорія дефектів на екрані невидима — інтерфейс їх приховує або просто не показує.
200 OK, а всередині помилка. Сервер повернув «успіх», але в тілі —{"error": "insufficient funds"}або порожній список замість даних. UI може відрендерити це як порожній екран, і тест «зелений». На рівні API ви бачите розбіжність статусу й тіла одразу.- Зайві поля у відповіді. Ендпоінт користувача повертає ще й
passwordHashчиisAdmin— фронтенд їх просто не показує, тож витік даних лишається непоміченим, поки хтось не гляне в сире тіло. - Валідація лише на фронтенді. Форма не пускає від'ємну кількість, але сам ендпоінт приймає
qty: -5без питань. Реальний зловмисник шле запит повз браузер — саме так треба тестувати й вам. - Доступ до чужих даних перебором id.
GET /api/orders/123віддає чуже замовлення, бо сервер не перевіряє власника (клас /BOLA). З UI такого посилання просто немає, а запит працює. - Гонки й неідемпотентність. Два однакові
POSTстворюють два замовлення; повторний платіж проходить двічі. Крізь UI такий сценарій відтворити важко, а прямими запитами — тривіально. - Неправильні статус-коди. На неіснуючий ресурс приходить
200замість404. Для користувача різниці немає, для клієнта API — критична. А от404замість403на чужий ресурс дефектом сам по собі не є: власник має право не підтверджувати існування ресурсу тим, у кого немає прав, — багом це стає лише за розбіжності із задокументованим контрактом конкретного API.
Саме ця категорія робить API-тестування обов'язковою навичкою, а не приємним доповненням.
Типові помилки
- Виглядає як «тест зелений, статус
200— усе працює», а насправді статус каже лише, що запит дійшов і сервер не впав; помилка може сидіти в тілі відповіді. Статус і тіло перевіряють окремо. - Виглядає як «UI не пускає невалідні дані, отже, бекенд захищений», а насправді валідація часто лише на фронтенді, і прямий запит проходить те, що форма блокує. Негативні перевірки треба слати повз UI.
- Виглядає як «API-тести швидкі й стабільні, замінімо ними всі UI-тести», а насправді API не бачить зламану верстку, неправильну прив'язку кнопки чи те, що помилка не показується користувачу. Рівні доповнюють, а не заміняють один одного.
- Виглядає як «поле не показується в застосунку, значить, його немає», а насправді відповідь може містити зайві чутливі поля, які фронтенд просто не рендерить. Дивіться сире тіло, а не екран.
- Виглядає як «GraphQL повернув
200, запит успішний», а насправді в легасі-режиміapplication/jsonстатус не є : реальні помилки лежать у масивіerrors, тож дивитися треба в тіло.
Підсумок
- API-тестування — це запити безпосередньо до інтерфейсу між компонентами, в обхід UI; воно швидше, стабільніше й бачить те, чого не видно з екрана.
- API-тести й UI-тести відповідають на різні питання й доповнюють один одного; API-рівень — «золота середина» піраміди й головний кандидат на автоматизацію.
- Об'єкт перевірки — п'ять зрізів: функціональність, дані, контракт, помилки, доступи.
- Типів API кілька (REST, SOAP, GraphQL, gRPC, вебхуки), і тестуються вони по-різному; статус-код сам по собі ніколи не є доказом успіху.
- Інструмент вибирають під задачу:
curl/Postman — для дослідження й відтворення, код — для регресії в CI.
Можливі питання
- «Чим API-тестування відрізняється від UI-тестування?» Інтерв'юер перевіряє, чи розумієте ви, що це різні зрізи, а не заміна: API — швидкість, стабільність і доступ до сирих даних/статусів; UI — увесь стек очима користувача. Слабка відповідь зводиться до «API без браузера»; сильна називає, що саме кожен рівень ловить, а другий пропускає.
- «Де API-тести в піраміді й чому саме там?» Хочуть почути про баланс вартості й стабільності: API-рівень покриває бізнес-логіку дешевше й надійніше за E2E, тому перевірки переносять якнайнижче.
- «Що ви перевіряєте у відповіді на запит?» Тут відсіюють тих, хто дивиться лише на статус. Сильний кандидат перелічує статус-код, тіло (значення й типи полів), заголовки, схему й побічний ефект (чи справді змінився стан).
- «Наведіть баг, який видно лише на рівні API.» Годяться
200з помилкою в тілі, валідація лише на фронтенді, зайві поля у відповіді, доступ до чужих даних перебором id. Конкретний приклад цінується вище за визначення. - «Чим ви тестуєте API?» Перевіряють кругозір і доречність:
curl/Postman для ручного дослідження, код у фреймворку для регресії в CI — і розуміння, коли переходити від одного до іншого.
Джерела
- Learn OpenAPI — Introduction (OpenAPI Initiative) — API визначає дозволені взаємодії між двома програмами; сторони — постачальник і , а сам API вважається непорушним контрактом.
- MDN — An overview of HTTP — HTTP як клієнт-серверний протокол: рівно два типи повідомлень — запит і відповідь, і ініціює їх отримувач ресурсу.
- ISTQB CTFL Syllabus v4.0.1 — перевірка інтерфейсів і взаємодій між компонентами — це інтеграційне тестування; окремого рівня «API testing» силабус не виділяє.
Чим API-тести відрізняються від тестування через UI
- Mike Cohn — The Forgotten Layer of the Test Automation Pyramid — три названі властивості тестів через інтерфейс — крихкі, дорогі, повільні — плюс четверта, забута: часткова надлишковість.
- MDN — An overview of HTTP — протокол не має стану: два послідовні запити нічим не повʼязані — звідси самодостатність окремого запиту в тесті.
- Roy T. Fielding — дисертація, гл. 5 (REST) — обмеження stateless: кожен запит містить усе потрібне для його розуміння, тож стан для сценарію готується одним запитом.
- Mike Cohn — The Forgotten Layer of the Test Automation Pyramid — першоджерело піраміди: рівнів три, модульні в основі, інтерфейс нагорі («we want to do as little of it as possible»), середній шар — забутий.
- The Practical Test Pyramid (Ham Vocke, martinfowler.com) — пізніший коментар: із піраміди варто винести два правила — тести різної гранулярності й тим менше тестів, чим вищий рівень.
- Martin Fowler — TestPyramid (bliki) — піраміда як збалансований портфель: низькорівневих тестів має бути значно більше за наскрізні.
- Software Engineering at Google — гл. 11: Testing Overview — деформації піраміди з назвами й причинами: «ріжок морозива» і «пісочний годинник».
- ISTQB CTFL Syllabus v4.0.1 — канон пірамідою не оперує: рівні розрізняються за обʼєктом, цілями, й відповідальністю.
Що саме перевіряємо на рівні API
- RFC 9457 — Problem Details for HTTP APIs — розділення шарів: статус-код несе загальну семантику для HTTP-софту, а тіло — специфіку API, на яку реагує клієнт.
- JSON Schema Validation, draft 2020-12 — зріз «дані»: схема стереже форму —
requiredперевіряє лише наявність імені властивості,formatтипово є анотацією. - OWASP API1:2023 — Broken Object Level Authorization — зріз «доступи»: перевірка прав на рівні обʼєкта має стояти на кожному ендпоінті, що приймає ідентифікатор.
- OWASP API Security Top 10 — 2023 — перелік 2023: BOLA — номер один, BFLA — доступ до чужих ресурсів і адміністративних функцій.
- Roy T. Fielding — дисертація, гл. 5 (REST) — REST як архітектурний стиль: ресурс — ключова абстракція, єдиний інтерфейс — центральна риса.
- RFC 9110 — HTTP Semantics — відображення CRUD на методи HTTP і статус-код як тризначне число, перша цифра якого задає клас.
- W3C — SOAP Version 1.2 Part 1: Messaging Framework — SOAP:
Envelopeз обовʼязковимBody, а помилка живе всередині повідомлення, не в коді HTTP. - SoapUI — SOAP and WSDL: Getting Started (SmartBear) — WSDL як строгий опис SOAP-сервісу, з якого генерують запити й .
- graphql.org/learn — Queries and Mutations — GraphQL: форму відповіді задає запит, дані повертаються під ключем
data, помилки — підerrors. - GraphQL Specification (October 2021) — специфікація GraphQL: відповідь описує результат виконання операції і всі помилки, що виникли під час запиту.
- gRPC — Core concepts, architecture and lifecycle — gRPC: відправна точка — опис сервісу у
.proto, а protocol buffers є дефолтом, а не властивістю протоколу. - gRPC over HTTP2 — протокольна специфікація — на дроті кожен виклик gRPC — це
POSTповерх кадрування HTTP/2, а результат лежить у трейлеріgrpc-status. - GraphQL over HTTP (робочий проєкт специфікації) — легасі-режим
application/json: вердикт про помилку читають із тіла, а не зі статусу.
Інструментарій: від curl до коду
- ISTQB CTFL Syllabus v4.0.1 — силабус говорить категоріями інструментів (проєктування й реалізація тестів, виконання й вимірювання ), а не брендами.
- OpenAPI Specification — специфікація сама називає інструменти тестування серед споживачів машиночитного опису API.
- Playwright — API testing —
APIRequestContextу Playwright: тестувати API, готувати серверний стан і перевіряти серверні пост-умови.
- ISTQB CTFL Syllabus v4.0 — : тести одночасно проєктують, виконують і оцінюють, вивчаючи тестовий обʼєкт; корисне за браку специфікацій і за дефіциту часу.
- ISTQB CTFL Syllabus v4.0.1 — чому саме регресія: регресійні ганяють багато разів, і кількість кейсів росте з кожною ітерацією.
- ISTQB CTAL-TAE Syllabus v2.0 — що дає автоматизація: те, чого руками зробити неможливо, — паралельність, віддалене виконання, консистентність між циклами.
Баги, які видно лише на рівні API
- RFC 9457 — Problem Details for HTTP APIs — статус повідомляє загальну семантику, а причину й деталі кладуть у тіло — звідси розбіжність «
200і помилка всередині». - OWASP API1:2023 — Broken Object Level Authorization — доступ до чужого обʼєкта: ідентифікатор легко знайти в шляху, query, заголовках чи тілі, і тип ідентифікатора значення не має.
- OWASP API Security Top 10 — 2023 —
API3:2023обʼєднує зайві дані у відповіді й mass assignment: спільна причина — брак перевірки прав на рівні властивості обʼєкта. - IETF Internet-Draft — The Idempotency-Key HTTP Header Field (-06) — дедуплікація повторів: генерує клієнт, а ресурс за ним впізнає той самий запит.
- MDN — 403 Forbidden —
404замість403легітимне: власник має право не підтверджувати існування ресурсу тим, у кого немає прав.
- RFC 9457 — Problem Details for HTTP APIs — статус і тіло — різні шари контракту, і жоден із них не є самодостатнім оракулом.
- GraphQL over HTTP (робочий проєкт специфікації) — у GraphQL розрив доведено до крайності: тіло читають незалежно від коду HTTP.
- Mike Cohn — The Forgotten Layer of the Test Automation Pyramid — рівні не заміняють один одного: тести через інтерфейс лишаються нагорі саме тому, що ловлять інше.
- OWASP API Security Top 10 — 2023 — зайве поле у відповіді й зайве поле в запиті — два боки одного ризику
API3:2023.
Що означає «тестувати API» і чим це відрізняється від тестування через UI?
API (application programming interface) — домовленість, через яку програми спілкуються між собою; у вебі це майже завжди HTTP-запит на URL з певним методом і тілом, на який сервер віддає , заголовки й тіло. Тестувати API означає звертатися до цього інтерфейсу напряму й перевіряти відповідь, без браузера і кліків: замість «заповнити форму й натиснути Save» ви шлете POST /api/orders з готовим JSON і перевіряєте, що прийшов 201, у тілі є id, а запис справді створився. Різниця з UI-тестом — у зрізі: тест через інтерфейс жене сценарій крізь браузер, верстку і JS до бекенду й бази, а API-тест б'є в бекенд без цього шару, тому виграє у швидкості й стабільності та бачить сирі дані, яких на екрані немає. Головне не плутати ці рівні: вони відповідають на різні питання, а не заміняють один одного.
На яке питання відповідає API-тест, а на яке — UI-тест?
UI-тест відповідає на питання «чи може користувач зробити X через інтерфейс?», API-тест — «чи коректно система обробляє дані й логіку?». За повноту стека UI-тест платить двічі: часом (рендеринг, анімації, очікування елементів) і крихкістю — його валить будь-яка зміна верстки, навіть коли логіка не чіпалася. API-тест бере вужчий зріз і тому виграє: десятки-сотні мілісекунд проти секунд, а зламати його може зміна контракту, не верстки. Але з цього не випливає «API краще»: кнопку можуть прив'язати до неправильного , поле — не відправлятися, помилку з API — не показати користувачу, і все це ловить лише UI-тест. Тому це розподіл праці, а не конкуренція.
Де стоять API-тести в піраміді тестування і чому саме там?
API-рівень — «золота середина» піраміди: посередині, між масою дешевих unit-тестів знизу й нечисленними повільними E2E через UI згори. Від E2E він виграє на порядок за швидкістю і стабільністю, а від unit відрізняється тим, що перевіряє не ізольовану функцію, а реально зібрану систему — з живим сервером, базою і серіалізацією. Бізнес-сценарій, що в UI розсипався б на десяток крихких кроків, тут закривається одним тестом. Звідси типова порада — переносити перевірки якнайнижче: усе, що можна перевірити на рівні API, не варто ганяти через браузер. Саме тому API-тести називають робочою конячкою більшості команд.
Що саме перевіряють на рівні API?
Об'єкт перевірки — п'ять зрізів. Функціональність: ендпоінт справді робить заявлене — створює, читає, оновлює, видаляє ресурс, рахує суму, застосовує знижку. Дані: форма і зміст відповіді — правильні типи полів, немає зайвого, дати й числа в очікуваному форматі. Контракт: API тримається домовленості з клієнтами й сусідніми командами — ті самі поля, статуси, зворотна сумісність. Помилки: реакція на невалідний ввід — зламаний JSON, відсутнє поле, неправильний тип, конфлікт — має бути осмисленим кодом і зрозумілим тілом. Доступи: хто що може — 401 без токена, 403 чужому користувачу, недосяжність чужих даних перебором id. Кожному зрізу далі присвячена окрема глава розділу.
Що ви перевіряєте у відповіді на запит?
Не лише статус — це головна пастка, на якій відсіюють слабких кандидатів. Перевіряють щонайменше чотири речі плюс побічний ефект. Статус-код — чи він осмислений для операції (201 на створення, а не просто 200). Тіло — значення й типи полів, відсутність зайвого, формат дат і чисел. Заголовки — Content-Type, Location на створеному ресурсі, заголовки кешу. Схему — чи відповідь структурно збігається з контрактом (типи, обов'язкові поля). І окремо — побічний ефект: чи справді змінився стан системи, тобто чи з'явився/зник запис у базі, а не тільки прийшла гарна відповідь. Статус і тіло перевіряють окремо, бо 200 каже лише, що запит дійшов і сервер не впав.
Чому статус 200 сам по собі не є доказом, що все працює?
Тому що статус повідомляє тільки долю транспорту — «запит дійшов, сервер не впав», а не коректність результату. Сервер може повернути 200 OK, а в тілі буде {"error": "insufficient funds"} або порожній список замість даних; UI відрендерить це як порожній екран, і тест «зелений». На рівні API ви бачите розбіжність статусу й тіла одразу, тому статус і вміст завжди перевіряють окремими . Крайній випадок — GraphQL: у легасі-режимі application/json статус не є , а реальні помилки лежать у масиві errors, тож дивитися треба в тіло.
Назвіть баг, який видно лише на рівні API.
Конкретний приклад тут цінується вище за визначення. Класика: 200 OK, а всередині {"error": ...} — UI малює порожній екран, дефект невидимий. Зайві чутливі поля у відповіді — ендпоінт користувача віддає ще й passwordHash чи isAdmin, фронтенд їх просто не рендерить, тож витік лишається непоміченим. Валідація лише на фронтенді — форма не пускає від'ємну кількість, а сам ендпоінт приймає qty: -5 без питань, бо реальний зловмисник шле запит повз браузер. Доступ до чужих даних перебором id — запит GET /api/orders/123 з чужим номером повертає не ваше замовлення, бо власника ніхто не звірив (клас /BOLA). Гонки й неідемпотентність — два однакові POST створюють два замовлення, повторний платіж проходить двічі. Неправильні статус-коди — на неіснуючий ресурс 200 замість 404. Через цей клас дефектів API-тестування і є обов'язковою навичкою, а не бонусом.
Чому «UI не пускає невалідні дані» не означає, що бекенд захищений?
Бо валідація часто живе лише на фронтенді, а прямий запит проходить повз неї. Форма блокує від'ємну кількість, порожнє обов'язкове поле чи надто довгий рядок — але це перевірка в браузері, і сам ендпоінт може приймати qty: -5 без питань. Реальний зловмисник (та й будь-який клієнт, що б'є в API напряму) обходить форму й шле сирий запит, тому негативні перевірки треба слати повз UI: curl або код прямо до ендпоінта з невалідним тілом. Добре спроєктований сервер на кривий ввід має свідомо відповісти 400/422, а не мовчки прийняти сміття й не впасти з 500.
Які бувають типи API і чому їх тестують по-різному?
Мінімальний набір для співбесіди — п'ять типів. REST — найпоширеніший стиль: система як набір ресурсів за URL, методи HTTP несуть дію, статус-коди несуть сенс; на нього спирається більшість розділу. SOAP — старіший і формальніший обмін XML-конвертами за строгим описом WSDL, живе в банках і телекомі. GraphQL — один ендпоінт, клієнт сам описує потрібні поля запитом; у легасі-режимі application/json статус не є оракулом, а помилки лежать у масиві errors. gRPC — бінарний RPC, який за замовчуванням серіалізує дані в Protobuf, у браузері як JSON не подивишся, потрібен grpcurl або код. Вебхуки (webhooks) — напрям зворотний: не ви шлете запит, а зовнішня система сама стукає HTTP-запитом на ваш URL, коли стається подія, тож для перевірки потрібен не клієнт, а . Різний транспорт, формат і напрям означають різні інструменти й різні пастки.
Чим тестують API — від curl до коду?
Інструменти вишиковуються в природну сходинку від разового пострілу до автоматизації. curl — HTTP-клієнт майже на кожній машині, ідеальний, щоб швидко перевірити один запит або вкласти точну команду відтворення в баг-репорт; -i покаже статус і заголовки. Postman — найпопулярніший графічний клієнт: колекції, змінні оточення, вбудовані скрипти-перевірки, командна робота; з нього зручно починати ручне дослідження. Insomnia — легша альтернатива з тією ж ідеєю, Bruno зберігає колекції звичайними файлами прямо в репозиторії, тож їх видно в git поряд із кодом. Верхня сходинка — код: коли перевірок десятки, вони мають ганятися в CI на кожен і сплітатися в ланцюжки (створити → прочитати → видалити), і тоді запити пишуть у тестовому фреймворку (у Playwright для цього є APIRequestContext). Інструмент вибирають під задачу, а не «раз і назавжди».
Коли API-тестування роблять руками, а коли автоматизують?
Руками (через Postman чи curl) — коли швидкість зворотного зв'язку важливіша за повторюваність: ви вивчаєте незнайомий API, робите дослідницьку перевірку гіпотези, відтворюєте баг або ганяєте одноразовий сценарій. Автоматизація виправдана там, де перевірки треба повторювати часто й однаково: , ланцюжки CRUD, запуск на кожен коміт у CI, перебір десятків комбінацій параметрів. API-рівень узагалі найвдячніший кандидат на автоматизацію — такі тести бігають швидко і не залежать від змін верстки. На практиці режими не конкурують: ручний прогін народжує перевірку, а в код іде те, що мусить ганятися постійно.
Чому «поле не показується в застосунку» не означає, що його немає у відповіді?
Бо фронтенд рендерить лише те, що йому потрібно, і мовчки ігнорує решту полів відповіді. Ендпоінт може повертати passwordHash, isAdmin, внутрішні прапорці чи чужі персональні дані — на екрані їх немає, але в сирому тілі вони є, і це готовий витік даних. Такий дефект неможливо побачити очима через UI; його ловлять, лише дивлячись на саму відповідь — у DevTools на вкладці Network, у curl -i чи в асерті автотесту на точний набір полів. Тому правило просте: перевіряйте сире тіло, а не екран, і асертьте не тільки наявність потрібних полів, а й відсутність зайвих.
Що таке IDOR і чому цей баг видно тільки на рівні API?
IDOR (insecure direct object reference; в OWASP API Security Top 10 той самий клас зветься BOLA — broken object level authorization) — це коли сервер віддає ресурс за прямим ідентифікатором, не перевіряючи, що запитувач є його власником. Практично: GET /api/orders/123 повертає чуже замовлення, бо перевірка авторизації на цьому ендпоінті пропущена — токен валідний, отже «пускаємо», а чий саме це запис, ніхто не звірив. З UI такого сценарію не відтворити: у чужого користувача просто немає посилання на цей ресурс, кнопки нема, шлях недосяжний. А прямим запитом він тривіальний — міняєш один id у URL і перебираєш. Тому перевіряти доступи треба саме на рівні API: залогінитися одним користувачем і спробувати дістати ресурс іншого, очікуючи 403 (або 404, якщо контракт навмисно ховає існування).
Ви шлете два однакові POST підряд — і створюються два замовлення. Про що це і як тестувати?
Це проблема ідемпотентності: повторення операції, яка мала виконатися один раз, дає повторний ефект — два замовлення, подвійне списання, дубль платежу. Крізь UI такий сценарій відтворити важко (треба дуже швидко клікнути двічі або зловити гонку), а прямими запитами тривіально: шлеш той самий POST двічі й дивишся, чи не з'явився дубль. Захист від цього — (Idempotency-Key) або серверна дедуплікація, і саме їх перевіряє негативний тест: два ідентичні запити з тим самим ключем мають дати один запис, а другий — повернути той самий результат, а не створити новий. Це та категорія багів, заради якої QA спускається під UI.
Чому неправильний статус-код (200 замість 404) — це дефект, хоча користувач різниці не бачить?
Тому що статус-код — частина контракту з клієнтом API, а не косметика для людини. Для користувача 200 на неіснуючий ресурс і 404 виглядають однаково (порожній екран), але клієнт-програма приймає рішення саме за кодом: 4xx — виправ запит, 5xx — сервер зламався, 404 — ресурсу немає, 401 — залогінься, 403 — прав немає. Неправильний код ламає цю логіку: клієнт не зробить , не покаже правильну помилку, не залогінить користувача заново. Окремий нюанс — безпека: 404 замість 403 власник має право віддавати свідомо, щоб не підтверджувати існування закритого ресурсу тим, у кого немає прав, тож перед асертом на код треба звірятися з контрактом конкретного API, а не з підручником.
Три ситуації з робочого життя QA, де рівень перевірки вирішує, чи побачите ви дефект: зелений UI поверх помилки в тілі, вибір рівня й інструмента під конкретну задачу, і доступ до чужих даних перебором id, який через екран не відтворити. Скрізь — що дивитися і чому.
Кейс 1. 200 OK, а всередині помилка
Тестувальниця оформлює замовлення через сайт: форма проходить, з'являється «Дякуємо за замовлення!», екран щасливий. Але в адмінці замовлення немає. Через UI все виглядає справним — і саме тут ховається дефект. Дивимося не на екран, а на сирий обмін: вкладка Network у DevTools або той самий запит через curl.
curl -i -X POST https://api.example.com/orders \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"productId": 42, "qty": 2}'
HTTP/1.1 200 OK
Content-Type: application/json
{"success": false, "error": "insufficient stock", "orderId": null}
Сервер повернув 200, і браузер чесно відрендерив «успіх» — фронтенд глянув лише на статус, а не на тіло. Насправді замовлення не створилося (orderId: null), товару не вистачило на складі. У коді ту саму розбіжність ловить один :
test('POST /orders: успіх підтверджують і статус, і тіло', async ({ request }) => {
const res = await request.post('/api/orders', {
data: { productId: 42, qty: 2 },
});
const body = await res.json();
// статус і тіло перевіряємо ОКРЕМО — 200 ще не означає створення
expect(res.status(), 'створення має відповідати 201').toBe(201);
expect(body.orderId, 'замовлення не створилося — orderId порожній').toBeTruthy();
});
Що дивитися і чому:
- Статус і тіло — це різні перевірки.
200каже лише, що запит дійшов і сервер не впав. Тут дефект подвійний: бекенд повертає200на бізнес-помилку (мав би409/422), а фронтенд орієнтується на статус замість тіла. Обидві складові варто зафіксувати в баг-репорті. - UI маскує розбіжність. Порожній екран, «успіх» без результату, зниклі дані — усе це на екрані виглядає невинно. На рівні API невідповідність статусу й тіла видно одразу.
curl -iдає точну команду відтворення. Її можна вкласти в баг прямо як є — розробник відтворить запит без здогадок про те, що саме натискала тестувальниця.
Кейс 2. Який рівень і який інструмент вибрати
Типова помилка початківця — усе перевіряти через браузер або, навпаки, повірити, що API-тести замінять UI. Рівні відповідають на різні питання; інструмент вибирають під задачу. Ось як розкладаються реальні перевірки з одного спринту:
| Задача | Рівень | Інструмент | Чому |
|---|---|---|---|
| Швидко глянути, що новий ендпоінт узагалі відповідає | API | curl | Разовий постріл, точна команда для баг-репорту |
| Дослідити незнайомий API, погратися з параметрами | API | Postman | Колекція, змінні оточення, ручні перевірки |
| Регресія CRUD-замовлення на кожен коміт | API | Код (Playwright) | Повторюваність, ланцюжки, запуск у CI |
| Перебрати 30 комбінацій знижок і меж | API | Код | Дешево й швидко там, де UI задихнеться |
| Чи показує форма помилку з бекенду користувачу | UI | Playwright (браузер) | Це видно лише через рендер |
| Чи не зламалася верстка сторінки оплати | UI | Playwright (браузер) | API верстки не бачить за побудовою |
Логіка вибору: спершу питаємо «на якому рівні живе те, що я перевіряю?». Бізнес-логіка й дані — вниз, на API; те, що бачить лише око користувача (верстка, показ помилки, прив'язка кнопки) — угору, на UI. Далі на рівні API питаємо «це разово чи постійно?»: разове дослідження — curl/Postman, постійна — код. Правило «переносити перевірки якнайнижче» означає: усе, що можна закрити на API, не варто ганяти через браузер — але не навпаки.
Кейс 3. Доступ до чужих даних перебором id (IDOR)
Замовлення відкривається за адресою /api/orders/{id}. Питання, якого не поставить UI: а що буде, якщо залогінений користувач попросить чужий id? З інтерфейсу такого посилання немає — кнопки нема, шлях недосяжний. Прямим запитом він тривіальний: береш свій токен і перебираєш чужі номери.
import { test, expect, request as apiRequest } from '@playwright/test';
test('чуже замовлення недосяжне за прямим id', async () => {
// 1) логінимося користувачем A, дістаємо його токен і id його замовлення
const alice = await apiRequest.newContext({
baseURL: 'https://api.example.com',
extraHTTPHeaders: { Authorization: `Bearer ${ALICE_TOKEN}` },
});
const own = await alice.get('/api/orders/1001');
expect(own.status(), 'своє замовлення користувач бачить').toBe(200);
// 2) тим самим токеном A пробуємо дістати замовлення користувача B
const foreign = await alice.get('/api/orders/2002');
// сервер має відмовити, а не віддати чужі дані
expect(foreign.status(), 'чужий ресурс мусить бути закритий').toBe(403);
});
Що дивитися і чому:
- Валідний токен ≠ право на конкретний ресурс. Найчастіша діра: сервер перевіряє «ти взагалі залогінений?» і пускає, але не звіряє «а це твій запис?». Валідний токен користувача A не має відкривати замовлення B.
- Очікуваний код — за контрактом. Тут асерт на
403(прав немає). Але частина API навмисно віддає404на чужі ресурси, щоб не розкривати сам факт їх існування, — тоді асертити треба404. Перед перевіркою звіряйтеся з контрактом конкретного API, а не з «як має бути за підручником». - Це не відтворити через UI. У чужого користувача немає ні кнопки, ні посилання на цей ресурс — сценарій існує лише на рівні прямого запиту. Саме тому доступи перевіряють на API, а не через браузер.
API vs UI: суть і межа рівнів
- Можу пояснити, що тестувати API — це слати запити прямо до інтерфейсу між компонентами, в обхід браузера й кліків.
- Знаю, що UI-тест проходить увесь стек, а API-тест заходить одразу в бекенд, оминаючи фронтенд, і тому швидший, стабільніший, бачить сире тіло.
- Розумію, що API-тест і UI-тест відповідають на різні питання й ловлять різне: лише UI бачить зламану верстку, криву прив'язку кнопки й непоказану користувачу помилку; лише API — сире тіло, статуси й доступи.
Піраміда і вибір рівня
- Розумію, чому API-рівень — «золота середина» піраміди: швидший і стабільніший за E2E, але, на відміну від unit, ганяє систему зібраною; один тест покриває бізнес-сценарій, що через UI тягнув би десяток крихких кроків.
- Можу пояснити правило «переносити перевірки якнайнижче»: усе, що перевіряється на рівні API, не варто ганяти через UI.
Об'єкт перевірки на рівні API
- Можу перелічити п'ять зрізів: функціональність, дані, контракт, помилки, доступи.
- Знаю, що у відповіді перевіряють не лише статус, а й тіло (значення й типи полів), заголовки, схему і побічний ефект (чи змінився стан).
- Розумію, чому статус
200сам по собі — не доказ успіху: він каже лише, що запит дійшов і сервер не впав, а помилка може сидіти в тілі.
Типи API і чим їх тестувати
- Знаю різницю REST vs SOAP vs GraphQL vs gRPC vs вебхуки за транспортом, форматом і напрямом запиту.
- Можу пояснити, чому в легасі-режимі
application/jsonстатус GraphQL не є , а помилки лежать у масивіerrors. - Розумію, що вебхук — це вхідний запит до вас, тож для перевірки потрібен , а не клієнт.
- Знаю, що gRPC бінарний (за замовчуванням Protobuf) і в браузері як JSON не подивишся — потрібен grpcurl або код.
Інструменти: від curl до коду
- Розумію сходинку інструментів:
curlдля разового пострілу й баг-репорту (-iпоказує статус і заголовки), Postman/Insomnia/Bruno для дослідження (Bruno тримає колекції файлами в git — зручно для рев'ю), код для в CI. - Можу пояснити, коли переходити від графічного клієнта до коду: десятки перевірок, запуск на кожен , ланцюжки CRUD.
- Знаю, що в Playwright для API-запитів є
APIRequestContext(request.post(...)), і що підглянути реальний запит застосунку можна у вкладці Network DevTools.
Ручне vs автоматизація
- Можу пояснити, коли API тестують руками (незнайомий API, дослідження, відтворення бага, разовий сценарій), а коли автоматизують (регресія, CRUD-ланцюжки, CI, перебір параметрів).
- Розумію, що ці режими не конкурують: руками формулюють перевірку, у код переносять те, що варто стерегти постійно.
Баги, які видно лише на рівні API
- Знаю приклад
200 OKз помилкою в тілі й можу пояснити, чому UI ховає цей дефект. - Розумію зайвих чутливих полів у відповіді (
passwordHash,isAdmin), яких фронтенд не рендерить, і валідацію лише на фронтенді — тому негативні перевірки шлють повз UI. - Знаю /BOLA (доступ до чужих даних перебором id), а також гонки й неідемпотентність (два
POST→ два замовлення) і неправильні як окремі класи багів рівня API.
Квіз
Перед стартом
- Питань: 14
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Що означає «тестувати API»?



