Якість і безпека
Основи тестування: що саме доводить перевірка
У главі 22 ми навчилися описувати критерій, сценарій, очікуваний результат, середовище й доказ до початку реалізації. Глава 47 показала, що окреме робоче…
У главі 22 ми навчилися описувати критерій, сценарій, очікуваний результат, середовище й доказ до початку реалізації. Глава 47 показала, що окреме робоче дерево не створює автоматично ізольовану серверну базу чи тестові дані. Тут розберемо, як різні перевірки знаходять різні дефекти, чому зелений результат завжди має межі та як не підмінити очікувану поведінку припущенням автора тесту.
Під тестом у цій главі маємо на увазі відтворювану дію з відомими передумовами й очікуваним спостереженням. Тестовий випадок (test case) описує один такий сценарій: початковий стан, дію та очікуваний результат. Набір тестів (test suite) збирає випадки для спільного запуску й звітування. Твердження (assertion) — явна перевірка очікуваного факту, наприклад «статус став cancelled». Джерело, за яким визначають очікуваний факт, називається тестовим оракулом. Ним може бути прийняте продуктове правило, контракт, інваріант даних, незалежно порахований результат або спостереження людини. Детальніше про план, оракул і середовище — у главі 22; тут ми зосередимося на виборі виду перевірки та тлумаченні її результату.
Дефект — недолік у вимозі, проєктному рішенні чи коді, який може спричинити неправильну поведінку. Симптом — те, що спостерігач бачить у конкретному запуску: наприклад, не той статус чи повідомлення про помилку. Очікувана поведінка — погоджений результат за визначених умов, а не те, що зараз повертає застосунок. Для помилки в правилі скасування симптомом може бути відмова власнику, очікуванням — дозвіл до часової межі; тестовий випадок має назвати ці вхідні умови та результат.
Тест може виявити дефект; успішний запуск показує лише, що конкретні твердження збіглися з результатом за конкретних умов. Він не доводить, що невідомих сценаріїв або невиявлених дефектів немає. Вичерпно перевірити всі входи, послідовності та середовища зазвичай неможливо.
48.1. Чотири питання до будь-якого тесту
Перш ніж довіряти зеленому індикатору, розберіть:
- Який дефект він здатний помітити? Зв’яжіть перевірку з конкретною поведінкою або ризиком, а не з назвою файла.
- Яку межу системи він перетинає? Одне правило, кілька компонентів, домовленість між сервісами чи шлях користувача через розгорнуту систему?
- Звідки взялося очікування? У тесті має бути правильна відповідь незалежно від коду, який він перевіряє.
- Які умови й підміни впливають на висновок? Дані, конфігурація, час, мережа, база даних, браузер, замінений сервіс і паралельні запуски.
Якщо ми не можемо відповісти на ці питання, слово «пройшов» ще не пояснює, який ризик знято. Тест може бути корисним і водночас не охоплювати сусідній сценарій.
48.2. Перевірка одного правила й три кроки тесту
Модульний тест (unit test) перевіряє одну невелику відповідальність у контрольованих умовах. «Модульний» не означає обов’язково один метод або один файл: суттєво, що саме ця перевірка не залежить від справжньої бази, мережі чи іншої зовнішньої системи. Такий тест дешевий і добре локалізує помилку в правилі. Але він не підтверджує, що застосунок правильно з’єднав правило з маршрутом, базою, правами й зовнішнім постачальником.
Поширений спосіб читати такий тест — Arrange–Act–Assert (підготуй — виконай — перевір; скорочено AAA): спочатку створити стан, потім один раз викликати поведінку, а тоді порівняти результат з очікуванням. Щоб порівняння часу не залежало від локальних налаштувань, приклад використовує UTC (Coordinated Universal Time — координований всесвітній час) для обох значень. Кожен рядок прикладу нижче пояснює, що він готує або доводить. Booking і can_cancel_booking — назви навчальної моделі та функції, які у справжньому проєкті відповідали б конкретному коду.
from datetime import datetime, timezone # Імпорт типів часу та зони з бібліотеки Python.
def test_owner_can_cancel_confirmed_booking_before_deadline(): # Назва фіксує правило, яке перевіряємо.
owner_id = "client-17" # Підготовка: створюємо стабільний синтетичний ідентифікатор власника.
actor_id = "client-17" # Підготовка: діяч має бути тим самим власником.
starts_at = datetime(2026, 10, 10, 10, 0, tzinfo=timezone.utc) # Підготовка: початок — 10 жовтня о 10:00 UTC.
now = datetime(2026, 10, 9, 9, 0, tzinfo=timezone.utc) # Підготовка: тепер — 9 жовтня о 09:00 UTC.
booking = Booking(owner_id, "confirmed", starts_at) # Підготовка: запис існує та ще підтверджений.
allowed = can_cancel_booking(booking, actor_id, now) # Виконання: викликаємо перевірюване правило один раз.
assert allowed is True # Перевірка: продуктове правило дозволяє власнику скасувати запис до межі.
Оракул тут — окремо сформульована вимога: власник може скасувати підтверджене бронювання, якщо до початку більше ніж 24 години. Приклад має 25 годин, тому незалежно очікуємо True. Ми не викликаємо перевірювану функцію вдруге, щоб порахувати очікуване значення. Якби обидва обчислення повторювали один і той самий дефект, тест міг би помилитися разом із кодом.
Слово «до» має бути продуктово визначене: що робити рівно на межі 24 годин? Зафіксуйте це в правилі й додайте випадок з точною межею; інакше різні тести можуть несвідомо очікувати > та >=. Ще два незалежні сценарії перевірять, що інший користувач не може скасувати чуже бронювання та що вже скасований запис не переходить у новий стан повторно. Один типовий успіх не відповідає на ці запитання.
pytest дозволяє перевіряти очікуване за допомогою звичного для Python оператора assert і показує деталі невдалого порівняння. Для порівняння чисел із допустимою похибкою слід задавати цю похибку явно. Можна також запускати наявні набори unittest: обидва підходи здатні співіснувати під час поступового переходу проєкту. Вибір рамки тестування сам по собі не робить оракул правильним. pytest: Assertions, pytest: unittest compatibility, Python: unittest — документацію перевірено 24 вересня 2026 року.
Приклад 1. Скасування бронювання: правило проти повної операції
Уявімо правило: лише власник має право скасувати підтверджене бронювання, якщо до початку лишилося більше 24 годин. Власник має побачити оновлений статус, а зміна має зберегтися.
Модульні тести функції дозволу можуть швидко перевірити власника, чужий обліковий запис, інший статус, крайні значення часу й саму межу. Вони локалізують помилки в логіці доступу та часу. Але True у такому тесті ще не доводить, що маршрут застосунку викликав функцію з ідентифікатором поточного користувача; так само він не каже, що оновлений стан потрапив у базу даних.
Інтеграційний тест (integration test) перевіряє взаємодію кількох реальних компонентів. Для того самого правила варто під’єднати тестовий маршрут, справжній сервіс і керовану тестову базу, створити синтетичне бронювання, виконати запит з обліковим записом власника, а потім прочитати запис зі сховища. Очікування визначають до запуску:
| Сценарій | Дія | Незалежне очікування | Що помітив би лише модульний тест |
|---|---|---|---|
| Власник і підтверджений запис за 25 годин до початку | Надіслати запит на скасування | Відповідь підтверджує успіх, стан у базі cancelled |
Не помітив би, що зміна не збереглася або маршрут передав не того користувача |
| Інший користувач і те саме бронювання | Надіслати запит від чужого облікового запису | Відмова; стан запису лишається confirmed |
Не помітив би зламану перевірку повноважень у маршруті чи запиті до бази |
| Власник рівно за 24 години до початку | Надіслати запит у визначеній межі | Результат відповідає погодженому правилу межі; стан не змінюється при відмові | Не помітив би різницю часу, точності або конфігурації годинника між шарами |
Таке інтеграційне покриття може виявити помилку транзакції, невідповідність полів моделі та схеми або застосування доступу лише на інтерфейсі. Воно все ще не перевіряє реальну пошту чи платіжний сервіс, якщо ті замінено. Тестова база має бути контрольованою й безпечною для запису та очищення; спільні дані або часовий пояс можуть змінити результат.
Слова «база в пам’яті» також не гарантують, що маршрут і тест бачать той самий стан. В SQLite кожне окреме відкриття :memory: за замовчуванням створює окрему базу; кілька з’єднань можуть ділити її лише з відповідним URI (Uniform Resource Identifier — уніфікований ідентифікатор ресурсу) і режимом спільного кешу. Отже, інтеграційний тест може читати іншу порожню базу, ніж та, куди записав застосунок. Це особливість саме такого способу використання SQLite, а не загальне правило для всіх сховищ. SQLite: In-memory databases, переглянуто 10 жовтня 2026 року.
48.3. Інтеграція та контракти між системами
Термін «інтеграційний тест» вживають для різних меж: два модулі, застосунок із базою чи взаємодія з іншим сервісом. Щоб назва була корисна, вкажіть, які компоненти справжні, що замінено, де проходить запит і який побічний ефект перевірено. Слово «інтеграційний» без цих деталей не описує доказ.
Контрактний тест (contract test) перевіряє домовленість між споживачем і постачальником повідомлень: які запити споживач надсилає і які відповіді має розуміти, або який формат повідомлення мають обидві сторони. Наприклад, клієнт календаря повинен надіслати часовий пояс і отримати погоджені поля часу та статусу. Такий тест може виявити різні назви полів, статуси, заголовки або правила серіалізації раніше, ніж повний розгортаний сценарій.
Контракт не є всією поведінкою системи. Схема може підтвердити, що поле status є рядком, але не те, що скасування справді звільнило слот. Контрактний тест повідомлень теж не перевіряє кожну бізнес-вимогу постачальника. Документація Pact описує контрактні перевірки як узгодження повідомлень на межі й окремо відрізняє їх від функціональних тестів побічних ефектів. Тому для сервісу бронювання контракт і тест збереження в базі відповідають на різні запитання. Pact: Introduction, Pact: Contract tests vs functional tests — переглянуто 10 жовтня 2026 року.
Приклад 2. Локальна підробка сумісна, постачальник — ні
Уявімо, що сервіс бронювання запитує зовнішній календар: «зайняти слот о 10:00». Локальний тест підміняє календар фікстурою, яка завжди повертає {"ok": true} у форматі JSON (JavaScript Object Notation — текстове представлення структурованих даних). Тим часом постачальник змінив реальну відповідь на {"status": "reserved"}. Код споживача все ще читає лише ok, вважає будь-яку неочікувану відповідь відмовою і не зберігає підтверджене бронювання. Локальний тест зелений, бо фікстура дослівно повторює старе очікування тесту; справжній обмін повідомленнями не відбувся.
Виправлення тут не обов’язково означає «прибрати всі підміни». Спершу зробіть явною домовленість: яка конкретна відповідь є успіхом, які поля обов’язкові, що означає конфлікт слотів і як клієнт поводиться з невідомим статусом. Контрактний тест має викликати справжній клієнт календаря, надіслати визначений запит до керованого тестового постачальника (mock provider) і перевірити обробку погодженої відповіді; той самий контракт має бути перевірений проти коду постачальника. Окремий інтеграційний тест із реальною тестовою базою підтверджує, що успіх або конфлікт правильно змінює локальний стан. Повний тестовий стенд за потреби перевіряє доступність розгорнутих сервісів.
Не слід називати цей вигаданий сценарій реальним інцидентом. Але проблема вірності тестової підробки має конкретний аналог: супроводжувачі controller-runtime пояснювали, що його фальшивий клієнт Kubernetes дозволяв зміні звичайного ресурсу оновити і статус, тоді як справжній клієнт розділяє звичайне оновлення й оновлення статусу. У запиті на злиття Pull Request (PR) №2259 змінили фальшивий клієнт і додали твердження про те, який стан має лишатися незмінним. Для пов’язаного випадку issue №2362 наводить відтворення, де тест із викликом звичайного Update не перевіряв помилку конфлікту, яку автор очікував від Status().Update. Це конкретні межі саме того тестового клієнта, а не доказ того, що всі фальшиві клієнти ненадійні. Сторінка PR вказує 0 перевірок; ми не робимо висновку, що зміна мала зелену автоматизовану збірку. controller-runtime issue №2230, PR №2259, issue №2362 — переглянуто 10 жовтня 2026 року.
Pact наголошує: клієнтський контрактний тест має викликати фактичний код клієнта, а не обходити його й напряму звертатися до тестового сервера. Інакше тест підтвердить поведінку тестового запиту, а не поведінку вашої інтеграції. Pact: Writing consumer tests, переглянуто 10 жовтня 2026 року.
48.4. Наскрізний сценарій і цінність користувача
Наскрізний тест (End-to-End, E2E) проходить важливий шлях через межі системи так, як його бачить користувач або інший клієнт: інтерфейс, застосунок, сховище та, за потреби, контрольовані зовнішні сервіси. Він може помітити, що компоненти окремо правильні, але разом не утворюють завершену дію.
Ціна цього охоплення — більше передумов і причин для нестабільності: браузер, розгортання, тестові облікові записи, дані, мережа, таймінг і залежні сервіси. Помилка може прийти з будь-якого шару, а її діагностика часто дорожча за модульний тест. Користуйтеся E2E для невеликої кількості найважливіших шляхів, а варіації правил і меж перевіряйте ближче до коду, де причину легше локалізувати.
Документація Playwright радить перевіряти видиму поведінку, ізолювати кожен браузерний контекст і уникати залежності від внутрішніх деталей реалізації. Новий BrowserContext ізолює стан браузера, як-от cookies і сховище сесії, але сам собою не створює окремої серверної бази й не прибирає спільний зовнішній обліковий запис. Приклад сесії в Flask нижче використовує HTTP (Hypertext Transfer Protocol — протокол передавання гіпертексту). Для асинхронного інтерфейсу повторне твердження чекає на очікувану умову; миттєве читання значення може побачити ще не оновлений стан. Повторне очікування не робить хибне очікування правильним і не усуває нестабільність мережі. Playwright: Best practices, Browser contexts, Assertions — переглянуто 10 жовтня 2026 року.
Перевірка димом (smoke test) — коротка перевірка, чи працюють критичні функції після розгортання. Регресійна перевірка шукає втрату раніше наявної поведінки після зміни. Це позначки мети перевірки, а не обов’язково окремі технічні рівні: модульний тест може бути регресійним, а E2E-перевірка — частиною короткого smoke-набору. ISTQB (International Software Testing Qualifications Board — Міжнародна рада з кваліфікації тестувальників програмного забезпечення) розрізняє рівні тестування, типи й перевірки, пов’язані зі змінами. Її модель корисна для словника, але не нав’язує кожній команді незмінний лінійний конвеєр. У різних практиках назви трохи відрізняються; описуйте межу, а не сперечайтеся про ярлик. ISTQB Foundation Level Syllabus v4.0.1, §2.2, датовано 15 вересня 2024 року; переглянуто 10 жовтня 2026 року.
48.5. Ручна перевірка й дослідження зручності
Ручне тестування потрібне не тільки для ситуацій, які «ще не встигли автоматизувати». Людина може помітити неочікувану поведінку, непорозуміння в тексті, візуальну перешкоду чи суперечність із реальним контекстом. Забезпечення якості (Quality Assurance, QA) охоплює практики, що зменшують ризик помилки; воно ширше за запуск тестів і не обов’язково означає окрему фінальну роль чи фазу.
Дослідницьке тестування (exploratory testing) поєднує вивчення продукту, розробку запитань і спроби знайти проблему. Людина може змінити маршрут, значення чи послідовність дій, побачивши нову підказку. Це цінно, коли поведінка маловідома або очікування ще не сформульовані. Щоб результатом можна було скористатися, фіксуйте мету, дані, послідовність, спостереження й те, що лишилося поза перевіркою. Автоматизований сценарій краще повторює вже обрану послідовність, але сам не вигадує невідому вимогу.
Стів Круґ наголошує на людському спостереженні за тим, як люди користуються інтерфейсом. Наприклад, кліки в тестовому браузері можуть пройти, хоча реальна людина не помічає кнопку, не розуміє повідомлення або не може відновитися після помилки. Модель чи сценарій, створений штучним інтелектом (ШІ), може допомогти підготувати запитання, але не є користувачем і не замінює спостереження за реальною поведінкою. Це не робить людське спостереження безпомилковим: спостерігач, завдання й учасники теж мають обмеження. Воно додає вид доказу, якого немає в перевірці селектора чи коду. Steve Krug: Rocket Surgery Made Easy, sample chapter, Sensible: downloadable testing resources — авторські матеріали; переглянуто 10 жовтня 2026 року.
Приклад 3. Успішний шлях приховує незрозумілу відмову
Автоматизований E2E-тест входить у застосунок як власник бронювання, натискає «Скасувати», підтверджує дію й бачить «Бронювання скасовано». Для звичайного сценарію це корисний доказ: видимий елемент, маршрут і запис взаємодіяли достатньо, щоб завершити дію.
Під час ручного дослідження сценарію «інший користувач відкриває посилання на чуже бронювання» тестувальник бачить код відповіді 403 (відмова в доступі), але повідомлення в інтерфейсі каже «Сталася невідома помилка. Спробуйте знову». Сервер зберіг дані правильно, однак користувач не розуміє, що доступу немає, і може повторити дію або звернутися до підтримки. Вимога про заборону доступу виконана, а критерій зрозумілої відмови — ні.
Після погодження очікуваного тексту його можна автоматизувати як перевірку видимої поведінки. Людське спостереження допомогло знайти критерій; автоматизований регресійний тест допомагатиме не загубити його далі. Це приклад послідовності, а не обов’язкова заміна ручної перевірки автоматизацією.
48.6. Фікстури, підміни й те, що вони приховують
Фікстура (fixture) задає повторно використовуваний початковий стан або ресурс для тесту: синтетичний користувач, ізольована база, тестовий браузер або контрольований годинник. Фікстура має визначати і створення, і очищення даних. Чим довше спільний ресурс живе між тестами, тим більша ймовірність прихованого зв’язку між ними. У pytest область фікстури може бути функцією, класом, модулем чи всією сесією; ширшу область слід вибирати свідомо, особливо якщо ресурс змінюється. Документація попереджає, що невдале налаштування фікстури може лишити частково створений стан і що автоматичного безпечного очищення не можна припускати. pytest: Fixtures, переглянуто 10 жовтня 2026 року.
Тестова підміна (test double) — загальна назва замінника залежності. Підвиди описують різні ролі, хоча в розмові їх часто плутають:
- Заглушка (stub) повертає наперед задану відповідь, щоб спрямувати тест до потрібного сценарію.
- Імітатор (mock) очікує певної взаємодії й перевіряє, чи її відбулося, наприклад що повідомлення відправили один раз із заданими даними.
- Фальшива реалізація (fake) має спрощену робочу поведінку, наприклад тимчасове сховище в пам’яті замість повноцінної бази.
- Підміна (spy) записує виклики для подальшого огляду, водночас дозволяючи поведінці продовжитися.
Визначення трохи відрізняються між джерелами. Для оцінки ризику важливіше запитати: що тест замінив, що справжнє залишилося й яку розбіжність заміна здатна приховати? Заглушка мережі не доводить сумісність із постачальником. Фальшива база може не відтворювати транзакцій, обмежень унікальності чи прав. Імітатор може підтвердити виклик методу, але не те, що викликаний сервіс успішно виконав дію. Заміна може бути правильною для ізоляції одного правила, але хибним доказом зовнішньої інтеграції.
Керований годинник допомагає перевірити межі без випадкового очікування добу; фіксоване зерно випадковості робить генерацію відтворюваною; унікальні ідентифікатори й очищення належать до ізоляції даних. Водночас годинник у підробці не виявить помилку часового поясу в базі, а серіалізатор у заглушці не підтвердить формат повідомлення в реальній мережі. У главі 47 розглянуто фізичне розділення робочих дерев для паралельних агентів; воно не ізолює автоматично спільну базу чи зовнішній акаунт. Тестові дані потребують окремих меж і власників.
48.7. Які сценарії додати
Розумний набір не перевіряє кожну можливу комбінацію. Він покриває класи входів і ризики, які здатні порушити обіцяне правило. Для важливої поведінки запитайте, чи є перевірка:
- успішного звичайного сценарію;
- відмови й побічного ефекту, якого при відмові не має статися;
- граничного значення правила;
- повторної дії або відновлення після переривання;
- паралельних запитів до одного слота, якщо це реально можливе: після одночасної спроби двох користувачів має залишитися не більше одного підтвердженого бронювання;
- різних ролей і власників даних;
- серіалізації та фактичного збереження, якщо вони на шляху;
- поведінки, видимої користувачеві, якщо критерій стосується зрозумілості.
Для доступу до бронювання не досить перевірити, що власник отримує свій запис. Додайте іншого користувача, який запитує той самий ідентифікатор. Очікування — відмова та незмінений запис. Інакше зібраний доказ стосується лише успішного читання, а не конфіденційності.
Якщо в календарі є рівно один вільний слот, запустіть два запити на його бронювання одночасно. Після завершення рівно одне бронювання має бути підтверджене; другий запит отримує погоджену відповідь про конфлікт. Перевірте результат у сховищі, а не лише статуси двох відповідей. Послідовні запити не відтворюють змагання за останній слот і можуть пропустити дефект блокування чи транзакції.
Перевірки можуть бути функціональними (чи виконується функція), нефункціональними (швидкодія, надійність, доступність, безпека) або зосередженими на структурі реалізації. Вони можуть запускатися на різних рівнях. Локальний запит до функції може перевірити логіку доступу, а навантажувальне тестування — межу продуктивності сервісу. Один вид не замінює інший лише тому, що всі мають статус «passed».
48.8. Перевірки коду й метрики не є доказом поведінки
Форматувальник перевіряє стиль тексту. Лінтер шукає задані категорії підозрілих конструкцій. Статична перевірка типів виявляє частину неузгодженостей типів без виконання коду. Збірка показує, чи вдалося перетворити проєкт на артефакт. Сканер безпеки шукає відомі класи ризиків. Усе це корисні перевірки, але жодна не відповідає сама по собі на питання: «Чи може інший користувач скасувати це бронювання?»
Покриття коду рахує, які рядки або гілки виконувались під час запуску. Воно допомагає знайти ділянки, до яких тестовий набір не дійшов. Воно не вимірює, чи правильний оракул, чи перевірено правильний стан, чи твердження здатне впасти на дефекті. Сто відсотків виконаних рядків сумісні з тестом, який викликав кожну функцію, але нічого не перевірив. Натомість нижче покриття може бути прийнятним, якщо критичні ризики перевірені незалежно; рішення має спиратись на ризик, а не на магічне число. Документація coverage.py окремо описує підрахунок гілок як вимірювання виконаного потоку керування, не семантичної правильності. coverage.py: Branch coverage measurement, переглянуто 10 жовтня 2026 року.
48.9. Нестабільний тест і точний звіт
Нестабільний тест (flaky test) іноді проходить, іноді падає за начебто однакової ревізії, бо результат залежить від часу, випадковості, порядку, спільних даних, паралельного запуску чи зовнішньої системи. Це симптом невизначеної умови або справжнього змагання за ресурс, а не доказ того, що помилка неважлива.
Повторний запуск допомагає зібрати свідчення, але кілька вдалих повторів не доводять, що перша відмова була хибною. Зберігайте перше падіння, ревізію, команду, середовище й журнали; перевірте, чи повторно використався той самий ресурс або чи змінився порядок. Не перемикайте статус на «пройшов», доки причина відмови не пояснена. Глава 22 розрізняє PASS (очікуване підтверджено), FAIL (результат відрізняється), FLAKY (результат змінюється між повтореннями), BLOCKED (запуску завадила передумова) і NOT RUN (не запускали); ця лексика вказує стан доказу, а не оцінку людини.
Розділіть також причину невдалого запуску. FAIL означає, що перевірений результат не збігся з очікуванням; це може бути регресія в продукті, але спершу треба перевірити і саме очікування та тестовий код. BLOCKED означає, що передумова чи інфраструктура завадила отримати результат. NOT RUN — сценарій не запускали. Пропущена перевірка так само не є успішною. Помилковий оракул може дати червоне попри правильну реалізацію, а справжній дефект — пройти тест, якщо очікування або межу перевірки підібрали невдало. Жодна з цих причин не виправляється простим перейменуванням статусу.
Звіт має називати ревізію коду, точну команду або сценарій, передумови, підміни та фактичний результат. Наприклад: «На коміті abc1234 пройшли 18 модульних тестів правила скасування з фіксованим годинником; інтеграція з календарем не запускалась, бо немає доступу до тестового постачальника». Такий звіт корисніший за «усе зелене», бо не перетворює відсутній зовнішній доказ на обіцянку.
ISTQB підкреслює, що тестування показує наявність дефектів, але не доводить їх повну відсутність. DORA (DevOps Research and Assessment — дослідницька програма DevOps) описує швидкі автоматизовані перевірки як важливу практику зворотного зв’язку, водночас визнаючи роль дослідницьких, приймальних і usability-перевірок людьми. Книга Accelerate: The Science of Lean Software and DevOps Ніколь Форсґрен, Джеза Гамбла та Джина Кіма є дослідницьким контекстом цього обговорення. Це не підстава оголошувати будь-яку конкретну піраміду тестів законом для кожної команди. DORA: Test automation, DORA: Continuous delivery, IT Revolution: Accelerate — переглянуто 10 жовтня 2026 року.
48.10. Тест, написаний агентом, теж потребує перевірки
Коли агент виправляє дефект і сам пише тест, він може повторити ту саму хибну інтерпретацію у двох місцях: код поводиться не так, а тест схвалює саме цю поведінку. Перед переглядом реалізації перевірте джерело очікування: вимогу, інваріант чи приклад, погоджений незалежно. Запитайте, чи впаде тест на старому дефекті, чи справді запускається цільовий код, і який сусідній сценарій не перевірено.
Якщо це можливо без побічного впливу, корисно виконати нову перевірку на ревізії до виправлення й переконатися, що вона падає саме з очікуваної причини. Після зміни перевірте її на зміненій ревізії. Це сильніше свідчення зв’язку між дефектом і тестом, але ще не доводить відсутність інших дефектів чи правильність самої вимоги. Не кожен випускний конвеєр зберігає попередній код для такого запуску; тоді перегляньте якість оракула, старий шлях у diff і відтворення з issue.
Документація Django для авторів змін рекомендує регресійний тест, який падає до виправлення й проходить після нього. OpenAI і Anthropic у своїх актуальних інструкціях роботи з кодовими агентами також радять називати перевірку та повідомляти, що реально запускалося. Це настанови виробників про конкретні інструменти й репозиторії; їх слід перетворювати на перевірювані умови звіту, а не на припущення про безпомилковість агента. Django: Writing your first patch, OpenAI: Prompting for Codex, Anthropic: Best practices for Claude Code — переглянуто 10 жовтня 2026 року.
48.11. Реальний дефект: IPv6 у Flask
У липні 2026 року повідомлення Flask issue №6093 описало неправильне розбирання адреси для IPv6, Internet Protocol version 6 (версія 6 інтернет-протоколу). У прикладі сервер очікував адресу на кшталт [::1]:8080, але поділ рядка за двокрапкою трактував сегменти неправильно. Автор проблеми навів вхідні приклади й зазначив, що запропоновані перевірки падають до виправлення; issue не містить збереженого виводу команди чи повного traceback, тож це треба приписувати повідомленню автора, а не подавати як незалежно збережений журнал запуску.
У PR №6096 Flask змінив розбір адреси та додав кілька цільових тверджень. Параметризований випадок перевіряє, що [::1]:8080 перетворюється на хост ::1 і порт 8080 у тесті запуску сервера, де мережевий виклик перехоплено. Інший тест проходить операцію сесії через тестовий клієнт застосунку з базовою адресою http://[::1]:8000/, зберігає значення й очікує відповідь із текстом 42. Ці тести показують очікуваний результат для конкретного синтаксису IPv6 у двох шляхах Flask. PR злитий; сторінка PR повідомляє 15 пройдених перевірок, а сторінка перевірок показує матрицю версій Python, платформ і статичних перевірок.
Межа доказу також важлива: перша перевірка ізольована й перехоплює запуск сервера, тому вона не доводить встановлення реального мережевого з’єднання. Тест сесії покриває взаємодію компонентів Flask у його тестовому клієнті, але не будь-яку IPv6-конфігурацію операційної системи чи мережі. Не приписуйте їм ширшу обіцянку, ніж дані в них перевіряють. Це і є дисципліна тестування: конкретний дефект, вхід, незалежне очікування, цільова перевірка та обмежений висновок. Flask issue №6093, Flask PR №6096, файли PR, перевірки PR — переглянуто 10 жовтня 2026 року.
Короткий підсумок
Обирайте тест за місцем ризику: модульна перевірка локалізує правило, інтеграційна перевіряє взаємодію реальних компонентів, контрактна перевіряє повідомлення між споживачем і постачальником, наскрізна проходить важливий користувацький шлях, ручне дослідження знаходить невідомі критерії та проблеми розуміння. Для кожного назвіть, що саме справжнє, що замінено і як визначене очікування.
Критерій і тест мають бути незалежними від реалізації, а звіт — прив’язаним до точного запуску й ревізії. Форматування, типи, збірка та покриття дають корисні сигнали, але не вимірюють повноту обіцяної поведінки. Зелений результат стосується того, що саме виконано; чесне «не запускали» або «заблоковано» точніше за загальне «все працює».
Джерела та подальше читання
- International Software Testing Qualifications Board, Certified Tester Foundation Level Syllabus v4.0.1 — моделі рівнів, типів і перевірок, пов’язаних зі змінами; версія від 15 вересня 2024 року.
- Python,
unittest; pytest, Assertions, unittest compatibility, Fixtures — тестові випадки, твердження та життєвий цикл фікстур. - SQLite, In-memory databases — межі окремих баз у пам’яті між з’єднаннями.
- Playwright, Best practices, Browser contexts, Assertions — видимі критерії, ізоляція браузера й асинхронні твердження.
- Pact, Introduction, Writing consumer tests, Contract tests vs functional tests — контракт на межі споживача й постачальника.
- DORA, Test automation, Continuous delivery; Nicole Forsgren, Jez Humble, Gene Kim, Accelerate — контекст автоматизації та зворотного зв’язку.
- Steve Krug, Rocket Surgery Made Easy, sample chapter, downloadable testing resources — людське спостереження за використанням інтерфейсів.
- Ned Batchelder, Branch coverage measurement — що саме підраховує покриття гілок.
- Kubernetes,
controller-runtimeissue №2230, PR №2259, issue №2362 — конкретні межі тестового фальшивого клієнта; у PR зазначено 0 перевірок. - Flask, issue №6093, PR №6096 — IPv6-дефект, цільові твердження й межа тестів.
- Django, Writing your first patch; OpenAI, Prompting for Codex; Anthropic, Best practices for Claude Code — настанови для відтворення регресії та звітування про перевірки в конкретних проєктах.
Усі мінливі сторінки, стани issue та PR перевірено 24 вересня 2026 року.