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

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

    Postman: основи

    Зміст

    Postman — найпоширеніший інструмент ручного API-тестування і майже гарантована тема співбесіди для trainee/junior: тебе можуть попросити прямо на дзвінку зібрати запит, підставити токен і додати перевірку. Але цінність Postman не в тому, що він «вміє надсилати запити» — це вміє й curl. Цінність у тому, що він перетворює купу разових запитів на організований, документований і повторюваний артефакт: колекцію, яку можна передати колезі, запустити цілком і навіть вбудувати в CI. Хто розуміє цю логіку, той відрізняється від кандидата, який «тикав у Postman» — і саме цю різницю перевіряє інтервʼюер.

    Ця глава — базова: структура, змінні, авторизація і перші перевірки. Скрипти, ланцюжки запитів, прогін із CSV та Newman — у наступній главі «Postman: скрипти, data-driven, Newman». Якщо ти вже щодня працюєш з API з коду і Postman тобі не потрібен — цю главу можна пропустити при першому проході й повернутися до неї перед співбесідою: питають про неї часто.

    Запит → папка → колекція

    Базова одиниця в Postman — запит (request): метод, URL, параметри, заголовки, тіло. Це рівно ті самі складові HTTP-запиту, які розібрані в главі «HTTP: методи, структура, заголовки» — Postman нічого не додає до протоколу, він лише дає зручну форму для його заповнення.

    Запити групуються в папки (folders), а папки — у колекцію (collection). Ієрархія проста, але за нею стоїть важлива ідея: колекція — це не «тека з файлами», а самостійний артефакт зі своїми налаштуваннями, документацією, авторизацією і змінними, які успадковуються вниз по дереву. Саме колекцію ти експортуєш у JSON, шариш команді, запускаєш цілком у Collection Runner чи Newman.

    Два поширені способи організувати колекцію:

    ПідхідСтруктураКоли доречний
    За ресурсами APIПапки Users, Orders, Payments — усередині CRUD-запитиДослідження API, регресійний набір, документація
    За сценаріямиПапки «Реєстрація», «Оформлення замовлення» — усередині кроки флоуНаскрізні бізнес-флоу, де запити залежать один від одного

    Обидва підходи робочі, головне — послідовність. І назви: запит Get user ні про що не каже, коли їх у колекції п'ятдесят. Краще називати за перевіркою або призначенням: «Створення користувача з валідними даними», «GET неіснуючого id → 404». Це той самий принцип, що й з тест-кейсами: назва описує, що перевіряємо, а не куди ходимо.

    Документування запитів

    У Postman кожен рівень ієрархії — колекція, папка, запит — має поле опису з підтримкою Markdown. Це виглядає як необов'язкова формальність, але насправді це найдешевша жива документація API в команді: опис лежить поруч із робочим запитом, а не в застарілому Confluence.

    Що варто фіксувати в описах:

    • На рівні колекції — що це за API, яке середовище потрібне, як отримати доступ (де взяти токен, кого просити про акаунт).
    • На рівні папки — контекст ресурсу чи сценарію: передумови, порядок виконання, відомі обмеження.
    • На рівні запиту — призначення, обов'язкові параметри, неочевидні значення полів, посилання на вимогу чи тікет.

    Другий інструмент документування — збережені приклади (examples). До запиту можна прикріпити пару «запит + відповідь»: реальну відповідь сервера зберігаєш як приклад, і тепер будь-хто бачить очікуваний формат тіла, не виконуючи запит і не маючи доступу до середовища. Приклади також живлять mock-сервери Postman — про це в наступній главі.

    З колекції Postman вміє згенерувати веб-документацію: описи, приклади і згенеровані фрагменти коду збираються в сторінку, яку можна опублікувати. Для QA це означає просту дисципліну: підтримуєш колекцію охайною — отримуєш документацію безкоштовно. Якщо ж у проєкті є специфікація OpenAPI, вона лишається первинним джерелом істини, а колекція — робочим інструментом поруч із нею (докладно — у главі «OpenAPI/Swagger: специфікація як джерело істини»).

    Environment і рівні змінних

    Уяви колекцію з п'ятдесятьма запитами, у кожному захардкоджено https://staging.example.com. Завтра треба прогнати те саме на dev — і ти редагуєш п'ятдесят URL руками. Це головний біль, який лікують змінні (variables).

    Змінна вставляється в будь-яке місце запиту через подвійні фігурні дужки: URL стає {{baseUrl}}/api/users, заголовок — Bearer {{token}}. Перед надсиланням Postman підставляє значення. А середовище (environment) — це іменований набір змінних під конкретний стенд: environment dev тримає свій baseUrl і token, environment staging — свої. Перемикаєш середовище в розкривному списку — і та сама колекція працює проти іншого стенда без жодної правки запитів.

    Змінні живуть на кількох рівнях (scopes), і це улюблене питання співбесід:

    • Global — видимі звідусіль, незалежно від колекції та середовища. Зручно для справді спільного (наприклад, версія API), небезпечно для всього іншого: глобальні змінні «протікають» між незв'язаними колекціями.
    • Collection — прив'язані до колекції та їдуть разом з нею при експорті. Гарне місце для констант, що описують сам API: базові шляхи, дефолтні значення полів.
    • Environment — прив'язані до стенда. Усе, що відрізняється між dev/staging/prod: хости, облікові дані, токени.
    • Local — існують лише під час виконання конкретного запиту чи прогону, задаються зі скриптів. Значення, які треба передати з одного запиту в наступний, зазвичай зберігають не в local, а в environment- чи collection-змінну — ланцюжки запитів це тема наступної глави.

    Є ще п'ятий скоуп — data: змінні з CSV/JSON-файлу під час data-driven прогону в Collection Runner (за пріоритетом — між environment і local). У щоденній роботі він не трапляється, тож докладно — у наступній главі.

    Коли одна й та сама назва визначена на кількох рівнях, перемагає вужчий скоуп:

    Global

    Collection

    Environment

    Local

    Значення, яке піде в запит

    Global

    Collection

    Environment

    Local

    Значення, яке піде в запит

    Тобто local перекриває environment, environment — collection, collection — global. Практичний наслідок: якщо «змінна не змінюється, хоч я її редагую» — майже напевно ти редагуєш її в одному скоупі, а запит бере значення з вужчого.

    Ще одна деталь, яку варто знати до того, як вона вкусить: у значення змінної є дві іпостасі — спільне (те, що синхронізується з командним воркспейсом і потрапляє в експорт) і локальне (тільки на твоїй машині). Класично Postman показував їх як два окремі поля — initial value (спільне) і current value (локальне); у нових версіях модель спростили — значення локальне за замовчуванням, а спільним воно стає лише коли ти його явно «шариш». Правило гігієни від зміни назв не залежить: секрети (токени, паролі) тримай лише в локальному значенні, а спільне лишай порожнім або з плейсхолдером. Інакше твій робочий токен поїде всій команді разом із колекцією.

    І остання пастка рівня «перший день із Postman»: якщо середовище не вибране або змінної в ньому немає, Postman не падає з помилкою — він надсилає запит із літеральним текстом {{baseUrl}} в URL. Зовні це виглядає як «сервер недоступний» чи дивна помилка резолвінгу імені, а насправді просто не підставилась змінна. В інтерфейсі нерозв'язана змінна підсвічується червоним — варто виробити звичку дивитися на це перед натисканням Send.

    Авторизація: auth helpers і спадкування

    Більшість реальних API вимагають автентифікації, і додавати заголовок Authorization руками в кожен запит — шлях до розсинхрону. Postman для цього має вкладку Authorization з готовими помічниками (auth helpers): Basic Auth, Bearer Token, API Key, OAuth 2.0 та інші. Помічник — це не окрема магія, а генератор: на основі введених даних він формує правильний заголовок (або query-параметр — для API Key це налаштовується) у момент надсилання. Сам механізм цих схем — Basic, токени, OAuth — розібраний у главі «Автентифікація та авторизація»; тут важлива інструментальна частина.

    Ключова можливість — спадкування (inheritance). Вкладка Authorization є не лише в запиту, а й у папки та колекції, і в кожного запиту за замовчуванням стоїть режим «Inherit auth from parent». Це означає: налаштуй авторизацію один раз на рівні колекції — і всі запити її отримають автоматично.

    Так

    Ні — власний auth

    Так

    Ні — власний auth

    Запит: Inherit auth from parent?

    Папка: Inherit auth from parent?

    Використати auth запиту

    Використати auth колекції

    Використати auth папки

    Так

    Ні — власний auth

    Так

    Ні — власний auth

    Запит: Inherit auth from parent?

    Папка: Inherit auth from parent?

    Використати auth запиту

    Використати auth колекції

    Використати auth папки

    Схема гнучка: колекція задає дефолт, окрема папка може його перекрити (наприклад, папка «Адмінські операції» ходить під іншим токеном), окремий запит — теж (запит «логін без токена» ставить собі No Auth). Разом зі змінними це складається в робочий патерн:

    1. Токен лежить в environment-змінній {{token}} (у current value).
    2. Авторизація налаштована один раз на колекції: тип Bearer Token, значення — {{token}}.
    3. Усі запити успадковують. Токен протух — оновлюєш одну змінну. Перемкнув середовище — під'їхав токен іншого стенда.

    Питання «де в Postman зберігати токен і як не дублювати його в 50 запитах» — класика співбесід саме тому, що відповідь вимагає скласти докупи обидві теми: змінні та спадкування. А функціональні перевірки самої авторизації — хто до чого має доступ, 401 проти 403 — окрема велика тема глави «Авторизація в API: ролі, доступи, негативні сценарії».

    Прості перевірки зі сніпетів

    Досі Postman був «зручним curl»: надіслав запит, очима глянув відповідь. Перший крок від ручної перевірки до автоматичної — тести: JavaScript-код, який виконується після отримання відповіді (вкладка Tests; у нових версіях Postman — Scripts → Post-response). Писати його з нуля не обов'язково: праворуч від редактора є панель сніпетів (snippets) — готових заготовок, які вставляються одним кліком.

    Мінімальний набір, з якого всі починають:

    // Сніпет "Status code: Code is 200"
    pm.test("Статус-код 200", () => {
        pm.response.to.have.status(200);
    });
    
    // Сніпет "Response body: JSON value check" (адаптований)
    pm.test("Створений користувач має числовий id", () => {
        const body = pm.response.json();
        pm.expect(body.id).to.be.a("number");
        pm.expect(body.email).to.eql("qa@example.com");
    });

    Що тут відбувається: pm.test оголошує іменовану перевірку, pm.response дає доступ до відповіді, а pm.expect — це асерт-бібліотека Chai, вбудована в Postman. Тест вважається пройденим, якщо жоден асерт усередині не впав. Результати з'являються у вкладці Test Results поруч із відповіддю: зелені passed, червоні failed з текстом помилки.

    Навіщо це, якщо можна глянути очима? Три причини:

    • Повторюваність. Перевірка виконується однаково щоразу — і коли запит запускаєш ти, і коли колега, і коли Collection Runner жене всю колекцію.
    • Захист від «200 OK з помилкою в тілі» — класичної пастки, коли статус успішний, а в тілі лежить помилка. Тест на конкретне поле тіла ловить це автоматично; докладно про пастку — у главі «Перевірки відповіді: статус, тіло, заголовки, схема».
    • Місток до автоматизації. Колекція з тестами — це вже прогінний набір: у наступній главі ці ж тести поїдуть у Collection Runner з CSV-даними та в Newman у CI.

    Важлива чесна межа: тести в Postman — це перевірки відповідей, а не повноцінний тест-фреймворк. Коли з'являються складні ланцюжки, спільні хелпери, code review тестової логіки — команди переходять на код (Playwright APIRequestContext, supertest тощо; огляд інструментів — у главі «API-тестування: об'єкт перевірки, рівні й інструменти»). Postman найсильніший у дослідженні API, ручних перевірках і швидкій регресії без інфраструктури.

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

    • Виглядає як «сервер лежить», а насправді не вибране середовище. Запит полетів з літеральним {{baseUrl}} замість хоста — звідси помилка з'єднання. Перша перевірка при дивних мережевих фейлах у Postman — чи підставились змінні (вони підсвічені червоним, якщо ні).
    • Виглядає як «Postman ігнорує мою змінну», а насправді конфлікт скоупів. Змінна з тією ж назвою визначена і в environment, і в колекції — редагуєш одну, а запит бере іншу, бо вужчий скоуп перемагає. Ліки: одна змінна — один дім, дублікати між скоупами не заводити.
    • Виглядає як зручність, а насправді витік секрету. Токен вписано у спільне (initial value) значення змінної або захардкоджено прямо в заголовку запиту — і він їде в командний воркспейс чи git разом з експортом колекції. Секрети живуть тільки в локальному (current value) значенні.
    • Виглядає як баг доступів, а насправді розсинхрон копій токена. Авторизація налаштована вручну в кожному запиті; токен оновили — половина запитів повертає 401. Ліки: спадкування від колекції плюс токен у змінній, одна точка оновлення.
    • Виглядає як покриття тестами, а насправді порожня обгортка. pm.test без жодного асерта всередині завжди зелений — тест, який нічого не перевіряє, гірший за відсутній, бо створює фальшиву впевненість. Кожен pm.test має містити хоча б один pm.expect або pm.response.to....

    Підсумок

    • Колекція — не тека, а артефакт: структура, документація, авторизація і змінні їдуть разом з нею при експорті, шарингу та прогоні.
    • Змінні мають рівні global → collection → environment → local, і вужчий скоуп завжди перекриває ширший; environment — стандартне місце для всього, що відрізняється між стендами.
    • Секрети — тільки в локальному значенні (current value): спільне значення (initial value) синхронізується з командою і потрапляє в експорт.
    • Авторизацію налаштовують один раз на рівні колекції через auth helper і змінну-токен; запити успадковують, окремі папки чи запити можуть перекрити.
    • Тести зі сніпетів (pm.test + pm.expect) перетворюють ручний перегляд відповіді на повторювану перевірку — це перший крок до Collection Runner і Newman.

    Що питають на співбесіді

    • «Які рівні змінних є в Postman і який пріоритет?» — очікують перелік global/collection/environment/local і правило «вужчий перемагає». Сильна відповідь додає практичний наслідок: чому дублікат змінної у двох скоупах — джерело плутанини.
    • «Як прогнати одну колекцію на dev і staging без правки запитів?» — перевіряють розуміння environment: хости й креденшали в змінних середовища, перемикання одним списком.
    • «Де зберігати токен авторизації?» — інтерв'юер дивиться, чи складеш ти докупи змінні + спадкування (environment-змінна, auth на рівні колекції) і чи знаєш про initial/current value та гігієну секретів.
    • «Як у Postman додати перевірку без написання складного коду?» — очікують сніпети, pm.test, перевірку статусу і поля тіла; плюс розуміння, що перевіряти статус недостатньо.
    • «Коли Postman перестає вистачати?» — питання на зрілість: сильний кандидат чесно окреслює межу (складні ланцюжки, review тестового коду, масштабна автоматизація → код) замість «Postman вміє все».

    Загальний фільтр інтерв'юера тут — чи розумієш ти систему (артефакт-колекція, скоупи, спадкування), чи просто запам'ятав, куди клікати.

    Джерела