vyvchy
    Теми розділу

    04 · API-тестування

    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-тест: увесь шлях

    Браузер

    Фронтенд

    API / бекенд

    База даних

    API-тест

    запит напряму

    UI-тест: увесь шлях

    Браузер

    Фронтенд

    API / бекенд

    База даних

    API-тест

    Ключова ідея вже на цій діаграмі: UI-тест проходить увесь стек — браузер, верстку, JavaScript, мережу, бекенд, базу. API-тест заходить збоку, одразу в бекенд, оминаючи весь фронтенд. Тому він швидший, стабільніший і бачить те, чого не видно з екрана.

    Чим API-тести відрізняються від тестування через UI

    «Чому» тут важливіше за «як». UI-тест відповідає на питання «чи може користувач зробити X через інтерфейс?» — і платить за це повнотою стека: він повільний, бо чекає рендеринг і анімації, і крихкий, бо ламається від зміни верстки, яка ніяк не стосується логіки. API-тест відповідає на інше питання — «чи правильно поводиться бізнес-логіка й дані?» — і за рахунок вужчого зрізу отримує швидкість і стабільність.

    АспектЧерез UIЧерез API
    Що перевіряєУвесь стек очима користувачаЛогіку й дані бекенду
    ШвидкістьСекунди на тестДесятки–сотні мілісекунд
    СтабільністьЛамається від зміни версткиЛамається від зміни контракту, а не верстки
    Що видноТільки те, що показує UIСтатус, усі поля тіла, заголовки
    Підготовка данихДовга, через кроки в UIШвидка, одним запитом

    З таблиці не варто робити висновок «API краще за UI». Вони відповідають на різні питання. Кнопка може бути прив'язана до неправильного ендпоінта, поле — не відправлятися, помилка з API — не показуватися користувачу: усе це ловить лише UI-тест. Тому це не заміна, а розподіл праці — і його формалізує піраміда.

    Місце в піраміді тестування

    Піраміда тестування — орієнтир, що показує, скільки тестів варто мати на кожному рівні. Знизу — багато дешевих і швидких модульних (unit) тестів; посередині — інтеграційні та API-тести; згори — мало повільних наскрізних (E2E) тестів через UI.

    E2E / UI — мало, повільні, крихкі

    API / інтеграційні — золота середина

    Unit — багато, швидкі, дешеві

    E2E / UI — мало, повільні, крихкі

    API / інтеграційні — золота середина

    Unit — багато, швидкі, дешеві

    API-рівень — та сама золота середина. Він на порядок швидший і стабільніший за E2E, але, на відміну від unit-тестів, ганяє систему зібраною: справжній сервер, справжня база, справжня серіалізація. Одним API-тестом ви покриваєте цілий бізнес-сценарій, який через UI тягнув би десяток крихких кроків. Тому типова порада — переносити перевірки якнайнижче: усе, що можна перевірити на рівні API, не варто перевіряти через браузер. Детальний розбір рівнів, вартості й антипатернів (як-от «пісочний годинник» чи «ріжок морозива») — у розділі «Автоматизація»; тут достатньо запам'ятати, що API-тести — робоча конячка більшості команд.

    Що саме перевіряємо на рівні API

    Об'єкт перевірки на рівні API — п'ять речей. Кожній далі присвячена окрема глава, тут — короткий орієнтир.

    Типи API оглядово

    «API» — не один протокол. На співбесіді корисно розрізняти хоча б п'ять і розуміти, чим тестування кожного відрізняється.

    ТипТранспорт і форматЩо характерно для тестування
    RESTHTTP + JSONРесурси й методи (GET/POST/PUT/DELETE), статус-коди несуть сенс
    SOAPXML поверх HTTPСуворий контракт (WSDL), громіздкі конверти, живе в enterprise/легасі
    GraphQLHTTP + JSON, один ендпоінтКлієнт сам описує запит; майже завжди 200, помилки — в масиві errors
    gRPCProtobuf поверх HTTP/2Бінарний формат, у браузері не подивишся як 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 віддає чуже замовлення, бо сервер не перевіряє власника (клас IDOR/BOLA). З UI такого посилання просто немає, а запит працює.
    • Гонки й неідемпотентність. Два однакові POST створюють два замовлення; повторний платіж проходить двічі. Крізь UI такий сценарій відтворити важко, а прямими запитами — тривіально.
    • Неправильні статус-коди. На неіснуючий ресурс приходить 200 замість 404, на чужий доступ — 404 замість 403. Для користувача різниці немає, для клієнта API — критична.

    Саме ця категорія робить API-тестування обов'язковою навичкою, а не приємним доповненням.

    Типові помилки

    • Виглядає як «тест зелений, статус 200 — усе працює», а насправді статус каже лише, що запит дійшов і сервер не впав; помилка може сидіти в тілі відповіді. Статус і тіло перевіряють окремо.
    • Виглядає як «UI не пускає невалідні дані, отже, бекенд захищений», а насправді валідація часто лише на фронтенді, і прямий запит проходить те, що форма блокує. Негативні перевірки треба слати повз UI.
    • Виглядає як «API-тести швидкі й стабільні, замінімо ними всі UI-тести», а насправді API не бачить зламану верстку, неправильну прив'язку кнопки чи те, що помилка не показується користувачу. Рівні доповнюють, а не заміняють один одного.
    • Виглядає як «поле не показується в застосунку, значить, його немає», а насправді відповідь може містити зайві чутливі поля, які фронтенд просто не рендерить. Дивіться сире тіло, а не екран.
    • Виглядає як «GraphQL повернув 200, запит успішний», а насправді GraphQL майже завжди відповідає 200, а реальні помилки лежать у масиві 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 — і розуміння, коли переходити від одного до іншого.

    Джерела

    • ISTQB® Certified Tester Foundation Level Syllabus v4.0 — розділ «Test Levels» (інтеграційне тестування, тестування взаємодії компонентів; окремої теми «API testing» силабус не виділяє): istqb.org.
    • MDN Web Docs — An overview of HTTP: developer.mozilla.org.
    • Martin Fowler — The Practical Test Pyramid: martinfowler.com/articles/practical-test-pyramid.html.
    • OpenAPI Specification — стандарт машиночитного опису REST API: spec.openapis.org.
    • GraphQL Specification: spec.graphql.org.