Якість і безпека
Test strategy: як скласти корисний набір перевірок
У попередній главі ми розрізнили локальні перевірки, інтеграційні перевірки та наскрізні сценарії. Тепер питання інше: які саме з них потрібні продукту,…
У попередній главі ми розрізнили локальні перевірки, інтеграційні перевірки та наскрізні сценарії. Тепер питання інше: які саме з них потрібні продукту, щоб команда могла змінювати його з обґрунтованою впевненістю?
Відповідь не дають ні кількість тестових файлів, ні число в звіті про покриття коду (coverage). Корисна стратегія починається з можливих відмов: що може піти не так, кому це зашкодить і який доказ вчасно виявить проблему. Потім вона враховує вартість перевірки, точність її сигналу й час, коли результат ще може вплинути на рішення про випуск.
49.1. Стратегія, план і сценарій — різні масштаби рішення
Три близькі поняття відповідають на різні запитання.
Стратегія тестування (test strategy) пояснює сталі принципи команди чи продукту: які ризики важливі, звідки надходить основний доказ, як поєднуються рівні перевірки, які вимоги мають проходити до випуску та як команда підтримує набір тестів. Вона змінюється, коли змінюються архітектура, ризики продукту чи спосіб постачання.
План тестування (test plan) застосовує ці принципи до конкретного випуску або зміни. Він називає обсяг, цілі, відповідальних, середовища, дані, послідовність, розклад і умови завершення. Міжнародна рада з кваліфікацій тестування програмного забезпечення (International Software Testing Qualifications Board, ISTQB) описує план як документ цілей, ресурсів і процесів для тестового проєкту та його календаря. Не кожна зміна потребує окремого формального документа: короткий план може бути частиною опису завдання чи запиту на включення змін (pull request), якщо потрібні рішення зрозумілі команді.
Тестовий сценарій (test case) описує одну конкретну перевірку: передумови, дію або вхідні дані та очікуваний результат. Наприклад: «користувач без входу відкриває приватний рахунок; відповідь не містить даних рахунку». Сценарій може бути автоматизованим тестом або ручною перевіркою; сам запис сценарію ще не доводить, що перевірку виконано.
Отже: стратегія визначає принципи, план — обсяг і послідовність конкретної роботи, сценарій — окремий випадок перевірки. Це корисна робоча відмінність, а не вимога зберігати три окремі файли. ISTQB також пов’язує тестову стратегію з планом: план показує, як команда дотримується стратегії або чому для конкретної ситуації від неї відступає. Силабус ISTQB CTFL (Certified Tester Foundation Level — базовий рівень сертифікації тестувальника) v4.0.1, 2024.
Добра стратегія не намагається перевірити все однаковим способом. Вона відповідає щонайменше на чотири запитання:
- Які помилки завдадуть найбільшої шкоди?
- Який рівень або вид перевірки здатен їх виявити?
- Наскільки швидким і надійним буде цей сигнал?
- До якого моменту результат потрібен, щоб команда могла безпечно діяти?
49.2. Піраміда — модель вартості й масштабу, а не норма відсотків
Піраміда тестування (test pyramid) — відома метафора набору перевірок. У класичному варіанті вона нагадує: вузькі перевірки однієї функції зазвичай дешевші й швидші, тож їх часто можна мати більше; перевірки, що проходять через значну частину системи, коштують дорожче й частіше залежать від середовища, тому їх добирають вибірково. Мартін Фаулер описує піраміду як спосіб мислити про збалансований набір і прямо називає важливу передумову: широкі тести зазвичай повільніші й ламкіші. Якщо ж у конкретній системі верхньорівневі перевірки швидкі, надійні й недорогі в супроводі, потреба в більшій кількості нижньорівневих перевірок може бути іншою. Test Pyramid, Martin Fowler, 2012.
Звідси не випливає універсальна частка модульних, інтеграційних і наскрізних тестів. Дві команди можуть мати набори різної форми й однаково добре контролювати свої ризики. Важливо знати, які припущення стоять за обраною формою, де виникає найдовше очікування і чи додає кожен дорожчий тест нову впевненість.
Рівень перевірки й спосіб взаємодії з інтерфейсом — не те саме. Користувацький інтерфейс (user interface, UI) — екран або інший спосіб, яким людина взаємодіє з продуктом; тест такого інтерфейсу може перевіряти невелику локальну поведінку компонента. Наскрізний тест (end-to-end, E2E — «від початку до кінця») перевіряє шлях через кілька частин системи й може спілкуватися із сервісом через програмний інтерфейс застосунку (Application Programming Interface, API), зовсім не відкриваючи браузер. Тому запитання «це тест UI?» не замінює запитань «яку частину системи він охоплює?» і «який ризик перевіряє?». У практичному посібнику Фаулера саме видимий користувацький інтерфейс і наскрізність названо характеристиками, що перетинаються, а не синонімами. The Practical Test Pyramid, Ham Vocke, 2018.
Є й моделі з іншим наголосом:
- Testing Trophy, або «трофей тестування», Кент Доддс запропонував як авторську підказку про окупність різних форм перевірки в JavaScript-застосунках. У ній під статичним аналізом і локальними тестами ширший акцент припадає на інтеграційні перевірки. Сам автор пов’язує образ із власним досвідом розробника інтерфейсів, а не з універсальним стандартом для будь-якого продукту. The Testing Trophy and Testing Classifications, Kent C. Dodds, 2021.
- Testing Honeycomb, або «стільник тестування», Spotify описує для мікросервісної архітектури, де ризик часто лежить у взаємодії сервісу з базою та його API. Їхня рекомендація — зосередитися на перевірках інтеграції всередині сервісу, залишити частину тестів деталей реалізації та звести до мінімуму тести, що залежать від інших реальних систем. У наведеному прикладі невеликий тестовий набір триває кілька секунд замість мілісекунд, потрібних вузьким тестам. Це вимірювання всього набору в конкретній архітектурі, а не порада механічно відмовитися від модульних тестів у звичайному вебзастосунку. Testing of Microservices, Spotify Engineering, 2018.
Google також радить мати добру основу вузьких тестів, не нехтувати інтеграційними перевірками й автоматизувати невелику кількість критичних наскрізних шляхів. Автор статті окремо зауважує, що потрібна глибина залежить від призначення продукту, цільової аудиторії та наслідків помилки. Це корисний орієнтир, не припис із фіксованим співвідношенням. How Much Testing is Enough?, Google Testing Blog, 2021.
Усі ці образи допомагають думати про вартість, швидкість, масштаб і довіру. Жоден із них не вимірює якість автоматично. Якщо команда сперечається лише про те, чи її набір «достатньо схожий на піраміду», вона може пропустити справжнє питання: який наслідок лишається без доказу?
49.3. Починайте з ризику, а потім обирайте перевірку
Ризик продукту — можливість, що дефект зашкодить користувачу, бізнесу чи іншій системі. Для порівняння ризиків можна якісно оцінити ймовірність відмови та її вплив. ISTQB описує ці виміри як основу оцінювання ризику; у кількісній моделі їх іноді перемножують, а якісну модель подають матрицею. Для щоденної стратегії часто достатньо послідовно узгодженої шкали «низький / середній / високий». Число на кшталт 12 із 25 не стає точним прогнозом лише тому, що його порахували. Мета — помітити важливі прогалини й першими перевірити ризики з тяжкими наслідками. [ISTQB CTFL v4.0.1, розділ 5.2](https://istqb.org/wp-content/uploads/2024/11/ISTQB_CTFL_Syllabus_v4.0.1.pdf).
Найчастіше варті явної уваги такі категорії:
| Що може піти не так | Який доказ може допомогти |
|---|---|
| Бізнес-інваріант порушено: знижку застосовано двічі, слот заброньовано двічі, статус переходить у неможливий стан | Локальні перевірки правила та, якщо воно залежить від сховища, інтеграційний тест на його реальну поведінку |
| Дані одного клієнта потрапили до іншого або користувач виконав заборонену дію | Негативні перевірки прав на межі API чи інтерфейсу з автентифікацією, відповідною роллю і даними кількох власників |
| Наш клієнт і постачальник послуги по-різному розуміють формат або значення відповіді | Контрактна перевірка на боці споживача та, коли доступна, перевірка цього контракту постачальником |
| Критичну послідовність дій неможливо завершити, хоча окремі компоненти працюють | Невеликий набір наскрізних перевірок найважливіших шляхів користувача |
| Перенесення даних пошкоджує записи або відновлення не повертає працездатний сервіс | Репетиція міграції на контрольованій копії даних, перевірка інваріантів, резервного відновлення та плану відкату |
Одна перевірка не завжди дає достатній доказ для серйозного ризику. Наприклад, локальний тест може підтвердити правильність формули комісії, але не доведе, що транзакція не зберігає неправильну суму або що користувач не побачить чужий рахунок. Тоді потрібні різні, бажано незалежні докази: тест правила, перевірка сховища, перевірка доступу на межі й огляд критичного рішення. Саме ризик, а не прагнення дублювати все на кожному рівні, пояснює, коли кілька перевірок виправдані.
49.4. Розміщуйте доказ там, де живе ризик
Рівень обирають не за престижем технології, а за механікою, яка може відмовити.
- Просте правило — наприклад, чи припустиме скасування до початку бронювання, — зручно перевірити локально на межових значеннях часу. Це дає швидкий і точний сигнал без браузера чи мережі.
- Взаємодія з базою даних потребує перевірки з реальною тестовою базою того самого типу або достатньо близького середовища. Підміна репозиторію не може довести, що саме база виконує обмеження унікальності чи транзакцій.
- Контракт між споживачем і постачальником описує зовнішню домовленість: поля, типи, обов’язкові значення, статуси та помилки. Тест із заздалегідь заданою відповіддю перевіряє, як поводиться наш код, але сам по собі не доводить, що сторонній постачальник іще віддає таку відповідь.
- Наскрізний сценарій перевіряє, що кілька частин продукту справді утворюють потрібний користувацький шлях. Його доцільно берегти для невеликої кількості шляхів із найбільшими наслідками, а не використовувати для кожної комбінації даних чи всіх варіантів одного правила.
Mock (мок, тестова підміна залежності) — об’єкт або сервіс, запрограмований на очікувану відповідь чи взаємодію. Він корисний, коли треба контрольовано перевірити, як наш компонент реагує на помилку мережі, тайм-аут або відповідь постачальника. Але якщо підміна повторює той самий неправильний контракт, яким керувався код, обидва тести можуть погодитися між собою й усе одно бути неправильними.
Тому підміни варто поєднувати з доказом на межі: контрактною перевіркою, офіційним ізольованим тестовим середовищем постачальника (sandbox) або контрольованим інтеграційним тестом. Під час такого тесту заздалегідь визначають дані, очищення та наслідки повторного запуску. Перевіряти робоче середовище (production) сторонньої системи можна лише з прямим дозволом її власника й узгодженими тестовими даними. У звичайній стратегії використовуйте sandbox або інший тестовий контур, а не справжні платежі, повідомлення клієнтам чи чужі робочі записи.
Вищий рівень має додавати новий доказ. Якщо модульний тест уже перевіряє всі варіанти формули тарифу, а десятки повільних браузерних тестів повторюють ті самі числа, браузерні перевірки мало що додають. Залиште локальні варіанти формули там, де вони швидко й зрозуміло виявляють помилку, а на вищому рівні перевірте те, що модуль не бачить: чи правильна сума проходить увесь шлях і показується користувачеві.
49.5. Приклад 1: компактна стратегія для сервісу бронювання
Уявімо сервіс, де користувач бронює кімнату на визначений інтервал. Помилково показаний календар створює незручність; подвійне бронювання втрачає довіру; витік адреси клієнта або підтвердження неіснуючого бронювання має серйозніші наслідки. Команда виписує правила й доказ для кожного ризику:
| Ризик | Де перевірити | Що має показати результат |
|---|---|---|
| Межі часу працюють неправильно: два інтервали, що торкаються краями, хибно конфліктують або перетинаються | Локальні сценарії функції, що порівнює інтервали; тестуємо однаковий часовий пояс і потрібні переходи літнього часу | Для суміжних інтервалів дозволено два записи; для фактичного перетину — ні |
| Два запити одночасно отримують той самий вільний слот | Інтеграційна перевірка через сервіс і тестову базу з двома конкурентними запитами | У сховищі є одне підтверджене бронювання; другий запит отримав узгоджений конфлікт, а не приховану помилку |
| Користувач читає чи скасовує бронювання іншої людини | Перевірка межі API з двома обліковими записами й даними обох власників | Доступ власника дозволений, доступ стороннього користувача відхилений згідно з продуктовою політикою; відповідь не розкриває приватні дані |
| Підтвердження листом відправлене до збереження бронювання або в неправильному форматі | Локальна перевірка формування події; інтеграційна перевірка запису події після підтвердження транзакції бронювання; перевірка контракту повідомлення з тестовим поштовим контуром | Лист не надсилається для відхиленого бронювання, а підтверджене має правильні дату, місце й одержувача |
| Відвідувач не може завершити основний сценарій у продукті | Один наскрізний сценарій: знайти слот, підтвердити бронювання, побачити результат | Користувач бачить те саме підтверджене бронювання, що збереглося в системі |
Окремі локальні сценарії швидко охоплюють межі часу й бізнес-правило. Перевірка конкурентних запитів запускає дві спроби, які починаються до того, як будь-яка з них зафіксує результат: в іншому разі тест випадково перевірить лише послідовну роботу. База має підтвердити інваріант навіть за одночасного доступу; успіх двох тестових підмін такого доказу не дає.
Для доступу команда фіксує, хто саме намагається виконати дію і яку саме дію. Тест адміністратора на власне бронювання не покриває випадку «звичайний користувач відкриває чужий запис». Для поштової інтеграції тестовий контур не відправляє клієнтам реальні повідомлення й не потребує облікових даних робочого середовища. Якщо тестовий контур недоступний, стратегія чесно позначає цей доказ як ще не отриманий, а не зараховує mock за реальну перевірку постачальника.
Результат — не «один тест на кожен шар», а компактний набір, кожна частина якого прикриває визначений ризик. Просту логіку запускають локально. Інтеграцію бази, конкурентний запис і права запускають у перевірці зміни. Контракт і критичний наскрізний сценарій також мають надійно пройти до випуску; ширші варіанти та відновлення даних виконують на відповідному тестовому контурі перед релізом. Якщо одна команда має швидке ізольоване тестове середовище й усі сценарії на ньому стабільні, вона може запускати більше перевірок раніше. Розклад залежить від фактичної вартості та довіри до сигналу.
49.6. Перевіряйте набір як програму: повторюваність і вартість
Автоматичний тест — теж код. Він може мати власну помилку, прихований спільний стан або залежність від нестабільного середовища. Нестабільним (flaky) називають тест, який за тієї самої ревізії коду може то проходити, то падати без відповідної зміни продукту. Типові джерела — очікування фіксований час замість очікування конкретного стану, залежність від порядку запуску, спільні записи в базі, локальний часовий пояс, несталий випадковий ввід, мережа або неповне очищення після попереднього сценарію.
Щоб сигнал повторювався, команда контролює саме ті чинники, що можуть змінити результат:
- передає годинник або часовий пояс у код, а не покладається на локальний час машини;
- явно задає випадкове зерно або записує ввід, якщо невдалий сценарій використовує randomness;
- створює ізольовані дані для кожного запуску й прибирає їх навіть після помилки;
- очікує на видиму умову або сигнал готовності, а не на довільну паузу «дві секунди»;
- робить кожен тест незалежним від випадкового попередника та перевіряє поведінку при паралельному запуску;
- обмежує мережевий доступ тестовими залежностями й записує версію середовища, коли вона може вплинути на результат.
Окремий повтор тесту допомагає діагностувати причину, але повторний успіх не стирає першу помилку. У звіті корисно розрізняти дефект продукту, помилку тесту, нестабільне середовище й невизначений результат. Якщо нестабільний тест тимчасово переводять у карантин, треба показати його статус, назвати власника, зареєструвати причину й строк виправлення та зберегти інший доказ для критичного ризику. Тест без власника й без плану швидко стає непомітно виключеною вимогою.
Досвід Meta показує масштаб, на якому стабільність тестів стає інженерною задачею: команда описала оцінювання ймовірної нестабільності (probabilistic flakiness score, PFS), яке могла застосовувати до мільйонів тестів. Компанія використовувала оцінку для пошуку й ремонту нестабільних перевірок. Її метрика й пороги — інструмент Meta для власної інфраструктури, а не готовий показник, який усі команди мають скопіювати. Важливий загальний висновок скромніший: довіра до тестового набору потребує спостереження та догляду. Probabilistic flakiness: How do you test your tests?, Meta Engineering, 2020.
Так само вартість треба вимірювати, а не вгадувати. У звіті Shopify про безперервну інтеграцію (Continuous Integration, CI) основного моноліту на той час ішлося про понад 170 тисяч тестів і понад 41 годину для повного запуску всіх тестів на одній машині. Команда виміряла час кожної команди й побачила, що 31% часу CI йшло на підготовку агентів, а ще 37% — на підготовку залежностей до запуску тестів. Тобто 68% часу CI в їхньому контексті витрачалося ще до тестування. Вони усували зайве повторне збирання, запускали вибрані пов’язані перевірки та додали зв’язок між тестами й файлами-фікстурами — наперед підготовленими наборами тестових даних. Автор звіту повідомив, що частка збірок, де не обирався весь набір, зросла з 45% до понад 60%, а стабільність — з 88% до 97%; кілька змін разом скоротили 95-й перцентиль (p95 — час, швидше за який завершилися 95% збірок) з 45 до 18 хвилин. Це ретроспектива Shopify з конкретною інфраструктурою. Вибірковий запуск має сенс лише настільки, наскільки карта залежностей повна: якщо зміна не потрапила до цієї карти, релевантний тест може просто не стартувати. Keeping Developers Happy with a Fast CI, Shopify Engineering, 2021.
49.7. Приклад 2: сотні повільних і нестабільних E2E-тестів
Уявімо мобільний застосунок для продавців. Набір із кількох сотень наскрізних тестів відкриває екран, входить у тестовий обліковий запис, редагує каталог і проходить оформлення замовлення. Перевірка часто займає довше за саму зміну. Частина помилок справжні, але частина з’являється, коли екран вантажиться довше або симулятор прокидається із запізненням. Команда звикає перезапускати набір, а потім починає ігнорувати червоні результати.
Перше рішення — не видаляти все наскрізне й не перемістити весь набір у нічний запуск. Команда класифікує кожен дорогий тест за ризиком і доказом:
- Повторені локальні правила. Десятки браузерних сценаріїв перевіряють одне й те саме обчислення податку, статус замовлення чи формат знижки, змінюючи лише цифри. Межові значення цього правила переходять у вузький тест модуля, а зв’язок модуля з базою — у швидкий інтеграційний тест. В одному наскрізному шляху залишається перевірка, що остаточна сума справді видима перед підтвердженням замовлення.
- Реальні користувацькі шляхи. Зберігаються сценарії, які перевіряють повну взаємодію застосунку з входом, каталогом і завершенням замовлення. На тестових платіжних даних вони не створюють реального списання. Читання користувацького інтерфейсу перевіряє те, що продавець може побачити й використати, а не лише наявність невидимого елемента у внутрішньому дереві компонентів.
- Причина нестабільності. Команда замінює сліпі паузи на очікування конкретного видимого стану, ізолює тестові облікові записи, перевіряє очищення й додає відео або журнал кроків. Для тесту в карантині називає власника й дату повернення. До повернення критичного сценарію випуск має інший доказ, який не дозволяє непомітно пропустити відповідний ризик.
- Послідовність запуску. Швидкі перевірки правил і найважливіші інтеграційні сценарії виконуються першими. Невеликий набір основних наскрізних сценаріїв має пройти до релізу. Повна матриця пристроїв і ширші варіанти запускаються після кожної зміни або перед випуском відповідно до їхньої вартості — але якщо реліз відбудеться раніше, повільна матриця не є доказом, отриманим до виходу.
Першоджерело Shopify дає практичний приклад такого розбору нестабільних мобільних наскрізних тестів (E2E). У найбільшому мобільному застосунку Shopify ці тести почали блокувати більше корисних змін, ніж поганих, і їх прибрали з обов’язкових перевірок запитів на включення змін. Частина тестів могла натискати на елемент, що був у внутрішньому дереві компонентів, навіть коли продавець не міг його побачити. Shopify побудувала суворішу обгортку навколо драйвера Appium, вимагала перевірки після кожної дії та використовувала комп’ютерний зір для пошуку видимих елементів. Через кілька тижнів після повернення нової системи в блокувальні перевірки компанія повідомила про стабільність 98% проти 50% у старого API тестового фреймворку. Це внутрішнє вимірювання Shopify для двох мобільних платформ, зокрема з фоновими помилками мережі та запуску симуляторів; воно показує результат їхньої перебудови, а не гарантію для іншого застосунку. How we raised mobile end-to-end test stability to 98%, Shopify Engineering, 2026.
Після сортування команда може видалити дубльований сценарій, якщо ризик справді має дешевший доказ і головний шлях лишився перевіреним. Сам факт, що тест повільний або інколи нестабільний, не достатній: це сигнал про проблему в тесті, середовищі чи дизайні продукту, яку треба зрозуміти. Видалення доречне після того, як команда назвала, який ризик тестувався, де його тепер перевіряють, коли проходить новий доказ і хто відповідає за повернення критичної перевірки. Для цієї навчальної команди результат видно у вимірюваннях до й після зміни: скільки часу минає до надійного результату, яка частка «червоних» запусків виявила реальну помилку й чи проходять критичні шляхи до випуску. Якщо тривалість впала, але справжній checkout лишився лише в нічному наборі після того, як команда вже випускає зміни, стратегія не закрила ризик. Такий поділ не потрібен, якщо всі наскрізні перевірки вже швидкі, стабільні й додають унікальний доказ.
49.8. Покриття коду не дорівнює покриттю ризиків
Покриття рядків коду (line coverage) показує, які рядки виконувалися під час тестів. Покриття гілок — чи перевірялися різні виходи з умов і циклів. Покриття вимог — чи має кожна важлива вимога пов’язаний сценарій і видимий результат. Покриття ризиків — чи є достатній доказ проти конкретної можливої шкоди. Ці виміри можуть перетинатися, але жоден не замінює інший.
Якщо тест запустив рядок return invoice, він довів виконання рядка, а не те, що користувач мав право читати рахунок. Навіть 100% покриття рядків означає лише, що кожен рядок був виконаний принаймні раз. Сила твердження тесту визначається тим, які умови він перевірив і який неправильний результат відкине. Силабус ISTQB окремо застерігає, що виконання оператора не гарантує виявлення дефекту; також повне покриття гілок і рядків не виявляє кожної помилки, залежної від конкретного шляху або даних. [ISTQB CTFL v4.0.1, розділ 4.3](https://istqb.org/wp-content/uploads/2024/11/ISTQB_CTFL_Syllabus_v4.0.1.pdf).
Тестування на основі властивостей (property-based testing) формулює правило, яке має залишатися правильним для цілого описаного діапазону даних, і перевіряє багато згенерованих прикладів. Наприклад: для будь-якого дозволеного списку інтервалів сортування не змінює склад списку; для будь-якої припустимої суми відсоткова знижка не збільшує її. Бібліотека Hypothesis пояснює підхід як властивість, що має виконуватися для всіх значень обраної області, і генерацію вхідних даних, яка знаходить також неочевидні крайні випадки. Це спосіб розширити пошук прикладів, а не доказ усіх можливих значень: область і саму властивість усе одно обирає автор. Hypothesis Documentation, версія 6.168.1.
Мутаційне тестування (mutation testing) змінює код маленькими контрольованими правками — наприклад, замінює > на >= — і запускає тести повторно. Якщо тестовий набір усе ще проходить, зміна могла показати прогалину в перевірках або зайву гілку коду. Cosmic Ray для Python описує цей підхід як спосіб перевірити, чи тести справді реагують на зміну поведінки. Але «вижилу» мутацію треба розглянути: вона може виявити слабке твердження, нерелевантний код або зміну, яка фактично не відрізняється в цьому контексті. Велика кількість мутацій також дорого коштує, тож такі перевірки зазвичай запускають вибірково на важливих правилах, а не ставлять обов’язковою умовою для кожного проєкту. Cosmic Ray Documentation.
Показник покриття корисний, якщо він відповідає на конкретне запитання: який код ще не виконується; які гілки не перевірені; чи є сценарій для кожної критичної вимоги; чи перевіряємо відмову, а не лише успіх. Якщо команда ставить мету «90% рядків» без прив’язки до поведінки, число може заохочувати додавати тести, які виконують код, але нічого важливого не стверджують.
49.9. Приклад 3: високе line coverage пропускає відсутню авторизацію
Уявімо API сервісу рахунків. Команда бачить 97% покриття рядків і вважає читання рахунків захищеним. Наявний тест входить як власник рахунку й виконує GET /invoices/83 — запит на читання запису з ідентифікатором 83 — та отримує правильну суму. Успішний сценарій проходить через маршрут, запит до сховища, форматування відповіді та відповідь клієнту — більшість рядків справді виконалися.
Але в реалізації забули перевірити власника запису. Запит до сховища шукає рахунок лише за його ідентифікатором, а не за парою «ідентифікатор рахунку плюс ідентифікатор облікового запису». Тест для власника залишається зеленим і тоді, коли така помилка є. Високий відсоток рядків не відповідає на запитання «чи може інший клієнт прочитати цей рахунок?».
Команда повертається до ризику й додає конкретні сценарії:
| Умова | Очікувана поведінка |
|---|---|
| Власник рахунку входить і читає свій запис | Отримує поля, передбачені продуктовою політикою |
| Неавтентифікований відвідувач запитує рахунок | Отримує відмову автентифікації; жодних даних рахунку у відповіді немає |
| Автентифікований власник іншого облікового запису запитує рахунок 83 | Отримує відмову або «не знайдено» — відповідно до політики приховування існування запису; приватні поля не повертаються |
Ключова перевірка проходить через справжній механізм автентифікації й тестове сховище, а не підміняє одночасно і користувача, і перевірку доступу. Тоді тест перевіряє пов’язану пару «хто просить / який запис просить». Його бажано написати так, щоб він червонів, якщо перевірку власника прибрати. Додаткова незалежна перевірка матриці ролей або огляд правил доступу доречні, бо ціна витоку висока. Водночас команда не копіює всі варіанти ролей у десятки повільних наскрізних сценаріїв, якщо інтеграційний тест на межі виявляє ці помилки швидко й надійно.
Після зміни можна звітувати про два різні факти: «97% рядків виконано» й «перевірено, що чужий клієнт не отримує даних рахунку». Друге — конкретне твердження про ризик. Перше — корисна, але обмежена характеристика виконання коду. Не слід підміняти одне іншим.
49.10. Розподіляйте перевірки в часі, не приховуйте пропущений доказ
Стратегія визначає не лише вид тесту, а й коли він має повернути результат. Виграш від швидкої перевірки зникає, якщо вона не впливає на рішення до того, як зміна дійде до користувача.
| Коли | Що зазвичай дає найкращий сигнал |
|---|---|
| Локально під час розробки | Швидкі перевірки змінених правил, статичний аналіз і ті інтеграційні тести, які легко запустити в тому самому середовищі |
| На кожну зміну чи pull request | Регресії зміненого коду, бізнес-інваріанти, права доступу, інтеграції з даними та обов’язкові контрактні перевірки; невеликий критичний набір наскрізних шляхів |
| Після злиття або в розширеному циклі | Повніші комбінації середовищ, сумісність, конкуренція, більший набір інтеграційних перевірок і тривалі навантажувальні сценарії |
| До випуску | Перевірка кандидата на випуск, міграції та відновлення, дозволених sandbox зовнішніх постачальників, а також тих критичних шляхів, які не входять до швидких перевірок |
| Після випуску | Спостереження за реальними показниками, помилками та доступністю; ізольовані синтетичні перевірки лише з контрольованими даними й дозволеним впливом |
Це орієнтир, а не обов’язкова кількість стадій у конвеєрі. Якщо весь набір досить швидкий і стабільний, команда може запускати його на кожну зміну. Якщо деякі перевірки дорогі, їх можна рознести за часом, але тоді треба чітко знати, який ризик лишається без сигналу до випуску. Вибірковий запуск за картою змінених файлів також може прискорити цикл; його безпечність залежить від якості цієї карти, обробки конфігурацій, фікстур і спільних компонентів. Перевірка, яку алгоритм запуску пропустив, не є перевіркою, що пройшла.
Дослідження DORA (DevOps Research and Assessment) описує безперервне тестування як перевірки протягом усього постачання, а не окрему фазу наприкінці. Його матеріали пов’язують короткий цикл зворотного зв’язку з можливістю швидше помічати й виправляти проблеми. Орієнтир «менше десяти хвилин» у рекомендаціях DORA варто читати як ціль швидкого сигналу для команди, не як універсальну межу, після якої якість гарантована. DORA також радить регулярно переглядати набір: тести мають виявляти дефекти й залишатися зрозумілими, а складність і вартість — контрольованими. Test Automation, Continuous Delivery, перевірено 24 вересня 2026 року.
У прочитаному фрагменті Accelerate Ніколь Форсгрен, Джез Гамбл і Джин Кім пов’язують коротший час постачання змін зі швидшим зворотним зв’язком, корекцією курсу й виправленням проблем. Практичний висновок для тестової стратегії: команда має спільно відповідати за якість, а перевірки вбудовувати в роботу так, щоб потрібний доказ надходив до рішення про випуск. Розробники підтримують автоматизований набір, а контроль якості триває протягом розробки й постачання. Це висновок про організацію потоку зворотного зв’язку, а не припис щодо кількості тестів чи частки кожного рівня. Авторський фрагмент Accelerate, сторінка видавця.
Прискорення не означає видалити «повільні» перевірки, потрібні для захисту важливого ризику. Спочатку виміряйте повний час до довіреного результату: підготовку середовища, завантаження залежностей, чергу до виконавця, тести й відновлення після нестабільності. Історія Shopify показує, що значна частина затримки їхнього конвеєра була підготовчими операціями, а не виконанням тестів; оптимізація повторної збірки й середовища дала виграш без послаблення тестових тверджень. У цьому сенсі швидкий фідбек — інвестиція в сам процес розробки, а не компроміс із потрібним доказом.
49.11. Агент змінює реалізацію, але не визначення успіху
Критерії тестової стратегії мають бути однакові незалежно від того, зміну пише людина, Codex чи Claude Code. Виконавець може запропонувати новий тест або помітити застарілий, але не повинен автоматично послаблювати регресійний набір тільки тому, що тест не проходить.
У запиті до агента варто пов’язати зміну з перевіркою: що саме має стати істинним, який негативний сценарій важливий, які команди дають доказ і що треба повідомити, якщо доказ недоступний. OpenAI у посібнику з роботи з цілями в Codex радить явно задавати результат, спосіб верифікації та обмеження; серед можливих джерел доказу називає тести й інші перевірювані артефакти. Anthropic у рекомендаціях для Claude Code так само радить дати агенту перевірку, яку він може виконати, і показати результат команди замість голослівного твердження про успіх. Це рекомендації для конкретних продуктів, а не гарантія, що агент обрав правильний тест або що тест покриває кожен ризик. Using Goals in Codex, OpenAI; Best practices for Claude Code, Anthropic.
Якщо агент пропонує вимкнути flaky-тест, попросіть його назвати: який ризик тест перевіряв; чи є дешевший або незалежний доказ; що не перевірено до випуску; хто й коли поверне тест або виправить його причину. Якщо агент додає тест, перевірте, що він падає саме на неправильній поведінці, а не лише збільшує coverage. Агент може швидко згенерувати багато схожих тестів, але обсяг тестового коду сам по собі не збільшує впевненість.
Короткий підсумок
Тестова стратегія пов’язує ризики продукту з доказами, які команда може отримати до потрібного моменту. Піраміда, трофей і стільник допомагають говорити про компроміс між швидкістю, масштабом, вартістю та точністю сигналу; вони не задають обов’язкової пропорції тестів. Рівень перевірки має відповідати механіці можливого дефекту: прості правила часто варто перевіряти локально, взаємодію даних — у тестовому середовищі з реальною базою, зовнішні домовленості — на контрактах, а ключову подорож користувача — невеликим числом справжніх наскрізних сценаріїв.
Покриття рядків або гілок показує, що виконувалося, але не підтверджує само по собі, що бізнес-вимога чи право доступу захищені. Стабільність тесту, його власник, контроль даних і час отримання результату так само важливі, як його назва. Якщо набір гальмує команду, виміряйте причину, відокремте дублікати від реальних шляхів і збережіть доказ для кожного суттєвого ризику.
Джерела та подальше читання
- International Software Testing Qualifications Board, Certified Tester Foundation Level Syllabus v4.0.1, версія 4.0.1 від 15 вересня 2024 року — план тестування, ризик-орієнтоване визначення обсягу й межі покриття коду.
- Martin Fowler, Test Pyramid, 1 травня 2012 року — походження й логіка моделі, її передумови та винятки.
- Ham Vocke, The Practical Test Pyramid, 26 лютого 2018 року — рівні, інтеграція, UI/E2E та запуск перевірок у конвеєрі.
- Kent C. Dodds, The Testing Trophy and Testing Classifications, 3 червня 2021 року — авторська модель окупності тестів для JavaScript-контексту й межі її застосування.
- Spotify Engineering, Testing of Microservices, 11 січня 2018 року — інтеграційно-орієнтований досвід для мікросервісної архітектури.
- George Pirocanac, Google Testing Blog, How Much Testing is Enough?, 15 червня 2021 року — поєднання локальних, інтеграційних і критичних наскрізних перевірок без претензії на універсальну кількість.
- Meta Engineering, Mateusz Machalica та співавтори, Probabilistic flakiness: How do you test your tests?, 10 грудня 2020 року — внутрішній підхід Meta до вимірювання й обслуговування нестабільних тестів.
- Christian Bruckmayer, Shopify Engineering, Keeping Developers Happy with a Fast CI, 24 лютого 2021 року — першоджерело про вимірювання й скорочення затримок конвеєра Shopify; показники належать до описаної тоді інфраструктури.
- Shopify Engineering, How we raised mobile end-to-end test stability to 98%, 12 серпня 2026 року — першоджерело про перебудову мобільних наскрізних тестів; відсоток — власне вимірювання Shopify.
- Nicole Forsgren, Jez Humble, Gene Kim, Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations, IT Revolution, 2018 — видавець і авторський фрагмент про час постачання, швидкий зворотний зв’язок і корекцію курсу; прочитано фрагмент, а не всю книжку; перевірено 24 вересня 2026 року: PDF.
- DORA, Test Automation та Continuous Delivery — практики надійних тестів, швидкого зворотного зв’язку й постійного перегляду набору; перевірено 24 вересня 2026 року.
- Hypothesis, Documentation, версія документації 6.168.1 — концепція тестування властивостей і генерації входів для описаної області; перевірено 24 вересня 2026 року.
- Cosmic Ray, Documentation — концепція мутаційного тестування й інтерпретації тестів, що проходять після змін коду; перевірено 24 вересня 2026 року.
- OpenAI, Using Goals in Codex — продуктово-специфічні рекомендації про результат, обмеження та видимий доказ виконання в задачах Codex; перевірено 24 вересня 2026 року.
- Anthropic, Best practices for Claude Code — продуктово-специфічна порада давати Claude Code виконуваний критерій перевірки й показувати доказ результату; перевірено 24 вересня 2026 року.
Дата доступу до всіх наведених джерел: 24 вересня 2026 року.