Генерація тест-артефактів
Зміст
Тест-артефакти (test artifacts) — це все, що QA продукує на папері й у коді: тест-кейси, чек-листи, тестові дані, автотести, баг-репорти. Рутина, яка з'їдає години: розписати п'ятнадцять кейсів на форму реєстрації, згенерувати сотню рядків тестових даних, перетворити ручний сценарій на скелет Playwright-тесту. Саме тут LLM (large language model) економить найбільше часу — і саме тут найлегше вистрелити собі в ногу.
Ця глава — про те, як віддати моделі чорнову роботу й не втратити якість. Ключова теза, яку варто винести наперед: AI видає чернетку, а не готовий артефакт. Модель генерує правдоподібний текст, а не перевірену істину, тож кожен її вивід проходить через тебе. На співбесідах це питають часто — не «чи вмієш попросити ChatGPT написати кейси», а «як ти перевіряєш, що згенероване не сміття». Це глава-поглиблення: на першому проході через розділ її можна пропустити й повернутися після базової глави «Промптинг для QA» — але надовго не відкладай, бо ваги на інтерв'ю вона має чимало.
Чому AI сильний у чернетках і слабкий у фактах
LLM працює як передбачувач наступного токена: вона продовжує текст найімовірнішим продовженням, спираючись на статистику мільярдів прикладів (механізм — у главі «Як працюють LLM»). Звідси випливає її профіль сил і слабкостей, і він прямо визначає, що їй можна доручити.
Модель сильна там, де відповідь має форму, а не факт: структура тест-кейсу, типові категорії перевірок для поля вводу, варіації тестових даних, boilerplate автотесту. Вона бачила тисячі таких артефактів і відтворює їхній шаблон швидко й охайно. Модель слабка там, де потрібна правда з-поза тексту: реальні селектори твого застосунку (вона їх не бачить — тож вигадає), справжній сенс вимоги, актуальна бізнес-логіка, фактичне покриття. Те, чого немає в промпті, модель добудує вигадкою — це галюцинація (hallucination), і виглядає вона так само впевнено, як і правда.
Практичний висновок один: доручай моделі широту й форму (швидко накидати багато варіантів у правильному форматі), а правильність і глибину лишай за собою. Далі — як це виглядає для кожного типу артефакту.
Тест-кейси і чек-листи з вимог
Спочатку розберемось із різницею, бо промпт під кожен артефакт свій. Чек-лист — це перелік того, що перевірити, без кроків: широта ідей. Тест-кейс — деталізований сценарій з передумовами, кроками й очікуваним результатом. AI добре дає перше (накидати тест-ідеї) і стерпно — друге (розписати кроки за твоїм шаблоном).
Щоб отримати корисний вивід, годуй модель тест-базисом (test basis) — вимогою, user story, критеріями приймання (acceptance criteria), а не просто назвою фічі. Порівняй: «напиши тести на логін» дає банальний happy path; «ось критерії приймання форми логіну (далі текст) — згенеруй чек-лист позитивних і негативних перевірок, згрупований за полями» дає структурований перелік, який лишається відрев'ювати. Явно проси негативні перевірки й крайові випадки — інакше модель тяжіє до щасливого шляху, бо його в навчальних даних більше.
Що модель дасть добре: широкий перелік категорій (порожні поля, невалідний email, довжина, спецсимволи, блокування після N спроб), охайне форматування, переклад ручних кроків у Given/When/Then. Що доведеться додати самому: перевірки, які випливають зі специфіки саме твого продукту (бізнес-правило «промокод не діє на розпродажні товари» модель не вигадає, бо його немає у вимозі, яку ти не дав). Техніки тест-дизайну — класи еквівалентності, граничні значення — детально розібрані в окремому розділі про тест-дизайн; тут важливо лиш, що їх можна й треба називати прямо в промпті (нижче).
Тестові дані: реалістичні, крайові, масові
Генерація тестових даних — те, де AI виграє найпомітніше, бо тут потрібна саме варіативність. Розрізняй три типи, бо кожен має свою мету:
| Тип даних | Мета | Приклад запиту до моделі |
|---|---|---|
| Реалістичні | Демо, скриншоти, «схоже на прод» | 20 користувачів з правдоподібними іменами й адресами |
| Крайові (boundary) | Зловити баги на межах і винятках | Порожній рядок, 256 символів, unicode, емодзі, '; DROP, від'ємна ціна |
| Масові (bulk) | Пагінація, продуктивність, ліміти | 10 000 записів для перевірки списку |
Реалістичні дані краще генерувати не «руками» моделі по одному, а попросити код із бібліотекою на кшталт faker — так дані детерміновані й відтворювані:
import { faker } from '@faker-js/faker';
// Масові дані: 10 000 користувачів для перевірки пагінації й продуктивності списку
const users = Array.from({ length: 10_000 }, () => ({
email: faker.internet.email(),
name: faker.person.fullName(),
createdAt: faker.date.past(),
}));
Крайові дані — навпаки, найцінніший ручний внесок: попроси модель окремим промптом «дай список підступних значень для текстового поля» й отримаєш готову базу злих рядків. Але двоє застережень. Перше: ніколи не давай моделі справжні персональні дані (PII) чи прод-дані — це витік; генеруй синтетику (детально — у главі про безпеку й приватність цього розділу). Друге: стратегія тестових даних — ізоляція, фабрики, прибирання між прогонами — це окрема велика тема (канон — у розділі про стратегію автоматизації); AI тут інструмент генерації, а не заміна стратегії.
Генерація автотестів
Найспокусливіше застосування — і найнебезпечніше. AI добре пише boilerplate: скелет Playwright-тесту, структуру page object, перетворення ручних кроків у код, параметризацію. На чому він гарантовано спотикається — селектори й перевірки, бо DOM твого застосунку він не бачить.
Ось типовий вивід, який виглядає робочим, а насправді фальшивий:
// Те, що часто видає AI: селектор вигаданий, перевірка нічого не доводить
await page.click('#submit-button'); // такого id у застосунку немає
await expect(page.locator('.result')).toBeVisible(); // «щось видно» — не «замовлення створене»
Селектор #submit-button модель узяла зі стелі — він статистично ймовірний, але у твоєму застосунку кнопка інша. А toBeVisible() на .result пройде, навіть якщо замовлення не створилось: видимість елемента ≠ правильний результат. Тест зелений, перевірки немає — гірше, ніж якби тесту не було зовсім, бо він створює хибну впевненість.
Після рев'ю той самий тест має спиратися на реальні, стабільні локатори й перевіряти справжній інваріант:
// Після доробки: рольовий локатор + перевірка реального результату
await page.getByRole('button', { name: 'Оформити замовлення' }).click();
await expect(page.getByText(/Замовлення № \d+ прийнято/)).toBeVisible();
Пріоритет стабільних локаторів (рольові, getByRole, data-testid замість крихких CSS/XPath) — окрема тема стратегії автоматизації; тут головне правило: селектори з AI-виводу треба звірити з реальним DOM, а не приймати на віру. Механіка перехоплення й перевірки запитів — у главі «Перехоплення й мокання мережі»; структура DOM і селекторів — у главі «DOM, селектори та події».
Техніки тест-дизайну в промпті й перевірка покриття
Якість виводу різко зростає, коли ти називаєш техніку прямо в промпті. «Застосуй аналіз граничних значень до поля age з діапазоном 18–65 і випиши 2-точкові межі» дає предметний результат замість загального переліку. Модель знає ці техніки з навчальних даних — їй бракує лише команди застосувати конкретну до конкретного поля. Так само працює «згенеруй таблицю рішень для правил знижки» чи «перелічи переходи станів для кошика».
Небезпека — у покритті (coverage). Модель залюбки напише «кейси покривають усі критерії приймання», і це твердження часто брехливе: вона його згенерувала, а не порахувала. Покриття перевіряєш ти, зіставляючи згенеровані кейси з вимогами (трасування, RTM — окрема тема тест-дизайну). Практичний прийом: попроси модель віддати вивід таблицею «критерій приймання → кейс, що його перевіряє», і прогалини стануть видимими самі — рядки без кейсу і є непокриті вимоги. Але фінальне рішення «покриття достатнє» лишається за людиною.
Що AI генерує погано
Окремо винесу межі — те, де на модель покладатися не можна навіть після хорошого промпта:
- Реальні селектори застосунку — вигадає, бо не бачить DOM.
- Тест-оракул (test oracle) — що є правильним результатом. Модель напише перевірку «сторінка завантажилась», але не знає, що після оплати баланс має зменшитись рівно на суму замовлення, якщо ти цього не сказав.
- Специфічну бізнес-логіку і доменні винятки — правила, яких немає у промпті. Їх треба дати або дописати руками.
- Справді нові тест-ідеї — модель інтерполює бачене, тож дає типове; несподівані діри у фічі, які й ловить сильний тестувальник, лишаються за нею.
- Проєктні конвенції — стиль ваших page object, назви методів, структуру репозиторію (якщо їх немає в контексті чи CLAUDE.md).
- Свіжі факти — API, версії бібліотек, синтаксис після knowledge cutoff моделі; звідси вигадані методи, яких у бібліотеці не існує.
Це не привід не користуватись — це карта, де тримати руку на пульсі. Глибше про природу цих помилок — у главі «Верифікація результатів AI».
Типові помилки
Виглядає як робочий тест, а насправді нічого не перевіряє. Зелений автотест без реальної перевірки: toBeVisible() на випадковому елементі, expect(true).toBe(true), асерт на статус 200 без перевірки тіла. Класика AI-виводу: код є, впевненості він не дає жодної.
Виглядає як точний локатор, а насправді вигадка. #submit-button, .btn-primary, getByText('Success') — правдоподібні рядки, яких у застосунку немає. Тест упаде на першому ж прогоні або, гірше, знайде не той елемент.
Виглядає як повне покриття, а насправді дублі. Модель схильна плодити варіації однієї перевірки під різними назвами: «невалідний email», «email без @», «неправильний формат пошти» — це один клас еквівалентності, а не три кейси. Широта є, унікальності немає.
Виглядає як усебічний набір, а насправді самий happy path. Без явного запиту на негативні й крайові сценарії модель тяжіє до щасливого шляху. Пів набору «перевірити, що все працює», жодного «перевірити, що ламається правильно».
Виглядає як факт, а насправді галюцинація. Метод бібліотеки, якого немає; посилання на неіснуючий пункт вимоги; впевнене «за стандартом має бути так». Модель не знає, що не знає.
Воркфлоу: генерація → рев'ю → доробка
Правильне використання AI для артефактів — це цикл, а не одна кнопка. Генерація дешева, рев'ю — ні; саме рев'ю лишається твоєю роботою й твоєю відповідальністю.
Три практичні правила циклу. Перше: вклади в промпт більше, ніж просиш назад — тест-базис, техніку, приклад бажаного формату (few-shot); дешевше дати контекст, ніж потім чистити вигадки. Друге: рев'ю за чек-листом, а не «на око» — селектори, реальність перевірок, покриття проти AC, дублі, галюцинації. Третє: виконання — фінальний фільтр: згенерований тест не «готовий», доки реально не прогнався й не показав, що падає з правильної причини. Останнє слово завжди за тобою: підпис під артефактом ставить людина, а не модель.
Підсумок
- AI видає чернетку, а не готовий артефакт — модель генерує правдоподібне, істину додаєш ти.
- Доручай моделі широту й форму (варіанти, boilerplate, форматування), лишай собі правильність і глибину (оракул, бізнес-логіка, реальні селектори).
- Годуй тест-базисом і назвою техніки в промпті — без цього виходить банальний happy path.
- Дві найнебезпечніші пастки автотестів: вигадані селектори й зелені перевірки, що нічого не доводять.
- Покриття, яке заявляє модель, — не факт, а текст: зіставляй кейси з вимогами сам.
- Робочий процес — цикл генерація → рев'ю → доробка → виконання, де рев'ю й відповідальність твої.
Що питають на співбесіді
- «Як ти використовуєш AI для написання тест-кейсів?» — інтерв'юер перевіряє, чи розумієш ти, що модель дає чернетку. Слабка відповідь: «прошу згенерувати й копіюю». Сильна: «даю вимогу і критерії приймання, називаю техніку, потім рев'юю на покриття, дублі й реалістичність, дороблюю доменні перевірки».
- «Які проблеми в AI-згенерованих автотестах?» — чекають на вигадані селектори й поверхневі перевірки (зелений тест без асерту). Плюс — якщо назвеш, чому це гірше за відсутність тесту: хибна впевненість.
- «Модель написала тест — він зелений. Твої дії?» — перевірка на «зелений ≠ правильний». Хочуть почути: подивитись, що саме перевіряється, чи впаде тест, якщо зламати фічу (мутація), чи реальні локатори.
- «Де AI НЕ можна довіряти в тестуванні?» — оракул, бізнес-логіка, свіжі факти/API, справді нові ідеї, PII у даних. Червоний прапорець для інтерв'юера — відповідь «AI усе зробить сам».
- «Як згенерувати тестові дані для X?» — розрізнення реалістичні/крайові/масові, детермінованість через
faker, і застереження про PII/прод-дані.
Джерела
- ISTQB Certified Tester Foundation Level (CTFL 4.0) — розділ 4 «Test Analysis and Design» і поняття тест-артефактів; фундамент, проти якого рев'юється будь-який згенерований кейс.
- ISTQB Certified Tester — AI Testing (CT-AI) — окремий силабус про тестування з AI і тестування AI-систем.
- Playwright — Best Practices — офіційні рекомендації щодо стабільних тестів і того, як мають виглядати перевірки.
- Playwright — Locators — пріоритет рольових і user-facing локаторів; еталон, з яким звіряєш селектори з AI-виводу.
Чому кажуть, що AI видає чернетку, а не готовий тест-артефакт?
Модель повертає правдоподібний текст, а не перевірену істину — і це різні речі. Технічно вона добирає найімовірніше продовження за статистикою прочитаного, тож охоче доповнює прогалини вигадкою, яка звучить так само впевнено, як факт. Для тест-кейсів це означає: структура буде охайна, категорії перевірок — типові, форматування — рівне, але за реальність селекторів, коректність бізнес-правил і фактичне покриття модель не відповідає. Тому вивід — стартова заготовка, яку ти доводиш до готовності, а не результат, який можна закомітити наосліп. На співбесіді цінують саме розуміння цієї межі, а не вміння натиснути «згенерувати».
Які тест-артефакти взагалі має сенс доручати моделі?
Тест-артефакти — це весь матеріал, який продукує QA: чек-листи, тест-кейси, тестові дані, скелети автотестів, баг-репорти. Доручати варто ту частину, де відповідь має форму, а не спирається на факт із-поза промпта: накидати багато тест-ідей, розписати кроки за твоїм шаблоном, згенерувати варіації даних, зробити boilerplate тесту. Ці речі модель бачила тисячі разів і відтворює швидко. А от правильність результату, доменні винятки й реальні локатори лишаються за тобою — це та частина, де форма не рятує. Простий орієнтир: широту й рутину — моделі, глибину й відповідальність — собі.
У чому різниця між чек-листом і тест-кейсом, і що з них AI дає краще?
Чек-лист — це перелік того, що перевірити, без деталізації кроків: чиста широта ідей. Тест-кейс — розгорнутий сценарій із передумовами, кроками й очікуваним результатом. Модель сильніша в першому: накидати два десятки тест-ідей по фічі їй легко, бо це задача на охоплення варіантів. Розписати повноцінні кейси за твоїм форматом вона теж може, але тут більше ризику — саме в кроках і очікуваних результатах ховаються вигадані деталі й підміна реальної перевірки формальною. Тому чек-лист від AI часто беруть майже як є, а кейси вимагають прискіпливішого рев'ю.
Що таке тест-базис і чому без нього промпт дає слабкий результат?
Тест-базис — це джерело, з якого виводяться перевірки: вимога, user story, критерії приймання, специфікація. Якщо годувати модель лише назвою фічі («напиши тести на логін»), вона добудує уявлення про фічу зі свого середнього досвіду й видасть банальний happy path. Даси критерії приймання й попросиш згрупувати позитивні й негативні перевірки за полями — отримаєш структурований перелік, прив'язаний до твоєї реальної вимоги. Різниця не косметична: без базису модель тестує абстрактний логін із інтернету, а не твій. Правило одне — вкладай у промпт контекст, який хочеш побачити відображеним у виводі.
Чому модель за замовчуванням тяжіє до happy path і як це виправити?
У навчальних даних позитивних сценаріїв «усе працює» просто більше, ніж негативних, тож без явної команди модель відтворює цю пропорцію й забиває вивід перевірками успіху. Виправлення пряме: окремо й наполегливо просити негативні та крайові сценарії — порожні поля, невалідний формат, перевищення довжини, спецсимволи, поведінку на межах. Корисно називати конкретні категорії, а не сподіватися, що модель здогадається. Практичний наслідок: у промпті на генерацію кейсів фраза «дай негативні й граничні перевірки окремим блоком» змінює склад набору сильніше, ніж будь-яке уточнення формату.
Які є типи тестових даних і коли який потрібен?
Розрізняють три типи, і кожен має свою мету. Реалістичні дані потрібні для демо, скриншотів і середовищ «схоже на прод» — правдоподібні імена, адреси, email. Крайові (boundary) націлені зловити баги на межах і винятках: порожній рядок, гранична довжина, unicode, емодзі, рядок на кшталт '; DROP, від'ємна ціна. Масові (bulk) перевіряють пагінацію, продуктивність і ліміти — умовні десять тисяч записів у списку. Плутати їх шкідливо: реалістичними даними не зловиш баг на межі, а масивом однакових рядків не перевіриш винятки. У промпті варто прямо називати тип, який тобі потрібен.
Чому реалістичні дані краще генерувати кодом з faker, а не «руками» моделі?
Коли модель вигадує двадцять користувачів прямо в чаті, результат неможливо відтворити: наступний прогін дасть інші імена, а тест на конкретне значення попливе. Код із бібліотекою типу faker розв'язує це — генерація стає детермінованою й повторюваною, з фіксованим seed її можна відтворити байт у байт, а обсяг масштабується однією зміною числа. Модель тут корисна інакше: вона швидко напише сам генератор, а не окремі рядки. Тобто просиш не «дай мені дані», а «дай код, що ці дані виробляє» — і отримуєш керований, версіонований інструмент замість разового списку.
Чому не можна віддавати моделі реальні прод-дані чи PII?
Усе, що ти вставив у промпт, покидає твій контур і потрапляє до зовнішнього сервісу — для персональних (PII) чи прод-даних це прямий витік, з юридичними й репутаційними наслідками. Тому реальні записи користувачів у промпт не йдуть узагалі, навіть «для реалістичності». Замість цього генеруй синтетику: faker чи окремий промпт «дай правдоподібні, але вигадані профілі» дають потрібну схожість без ризику. Це не перестраховка, а базова гігієна роботи з зовнішньою моделлю — тема безпеки й приватності стоїть окремо саме тому, що ціна помилки тут висока.
Що AI пише добре в автотестах, а на чому гарантовано спотикається?
Добре йому даються boilerplate і структура: скелет Playwright-тесту, каркас page object, переклад ручних кроків у код, параметризація однотипних перевірок. Це форма, яку модель бачила тисячі разів. Спотикається вона на двох речах — селекторах і перевірках, бо DOM саме твого застосунку їй недоступний. Селектор вона добере статистично ймовірний (умовний #submit-button), але у твоєму інтерфейсі кнопка інша, і тест упаде або, гірше, зачепить не той елемент. А перевірку напише формальну — «щось видно», — яка не доводить справжнього результату. Тому каркас беруть від моделі, а локатори й асерти доводять руками проти реального застосунку.
Чому зелений AI-згенерований тест може бути гіршим за відсутність тесту?
Бо він створює хибну впевненість. Уяви асерт toBeVisible() на випадковому елементі або перевірку статусу 200 без жодного погляду в тіло відповіді: тест зелений, у звіті — галочка, але він пройде навіть тоді, коли фіча зламана. Відсутній тест хоча б чесний — усі знають, що ділянка не покрита. Фальшиво-зелений бреше: команда вважає функціонал перевіреним, реліз їде, баг проходить крізь пусту перевірку. Саме тому «зелений» і «правильний» — не синоніми, і рев'ю AI-виводу насамперед шукає перевірки, які нічого не доводять.
Що таке вигаданий селектор і як його спіймати?
Це локатор, який модель згенерувала за статистичною ймовірністю, а не з реального DOM: правдоподібні #submit-button, .btn-primary, getByText('Success'), яких у застосунку немає. Виглядає переконливо, бо такі рядки часті в навчальних даних, але зачіпки в конкретному інтерфейсі під ним немає. Ловиться просто — звіркою з живим DOM: відкрити сторінку, знайти справжній елемент, підставити стабільний локатор. Симптом на прогоні теж упізнаваний: тест падає на першому ж кроці «елемент не знайдено» або мовчки чіпляє не той вузол. Загальне правило — жоден селектор із AI-виводу не приймається на віру, лише після перевірки проти реального застосунку.
Що таке тест-оракул і чому модель його часто не знає?
Тест-оракул — це джерело правильної відповіді: що саме має статися, аби вважати результат коректним. Модель напише поверхневий оракул («сторінка завантажилась»), але глибокого інваріанта не вгадає, якщо його немає у промпті: що після оплати баланс зменшується рівно на суму замовлення, що номер створеної заявки з'являється в списку, що лист пішов саме на цю адресу. Причина проста — це правда з твоєї бізнес-логіки, а не з тексту, який модель бачила. Практичний наслідок: слабку перевірку «щось відрендерилось» доводиться замінювати перевіркою реального ефекту, і саме цю частину людина дає моделі або дописує сама.
Як назва техніки тест-дизайну в промпті змінює якість виводу?
Різко на краще, бо перетворює загальний запит на предметний. Модель знає класи еквівалентності, аналіз граничних значень, таблиці рішень і діаграми переходів станів із навчальних даних — їй бракує лише команди застосувати конкретну техніку до конкретного поля. Порівняй «напиши тести на вік» і «застосуй аналіз граничних значень до поля age з діапазоном 18–65 і випиши двоточкові межі»: друге дає адресний, перевірюваний перелік замість розпливчастого. Так само працюють «побудуй таблицю рішень для правил знижки» чи «перелічи переходи станів кошика». Тобто техніка — це важіль керування виводом, і називати її треба явно.
Чому заяві моделі «кейси покривають усі критерії приймання» не можна вірити?
Бо це речення вона згенерувала як правдоподібний текст, а не порахувала як факт. Модель однаково впевнено напише «покрито всі AC» і в разі, коли половина критеріїв лишилась без жодного кейсу — вона не звіряла, вона продовжила фразу. Покриття рахує людина, зіставляючи згенеровані кейси з вимогами. Зручний прийом — попросити вивід таблицею «критерій приймання → кейс, що його перевіряє»: рядки без кейсу самі показують діри. Але фінальне рішення «покриття достатнє» лишається за тобою, бо трасування вимог до перевірок — це судження, а не текст, який можна замовити в моделі.
Модель написала тест, він зелений. Які твої наступні дії?
Спершу прочитати, що саме він перевіряє: чи є реальний асерт на результат, чи це формальне toBeVisible()/статус 200 без тіла. Далі — мутаційна перевірка: свідомо зламати фічу (прибрати кнопку, зіпсувати розрахунок) і переконатися, що тест почервонів; якщо він лишається зеленим на зламаній фічі, він не перевіряє нічого. Потім звірити локатори з живим DOM — чи вони реальні й стабільні, чи вигадані. І тільки тест, який падає з правильної причини й спирається на справжній інваріант, можна вважати робочим. «Зелений» тут — не доказ, а привід придивитися.
Де в тестуванні AI не можна довіряти навіть після хорошого промпта?
Є стійкий перелік сліпих зон. Реальні селектори — вигадає, бо не бачить DOM. Тест-оракул — не знає, який результат правильний, поки ти не сказав. Специфічна бізнес-логіка й доменні винятки — правил, яких немає у промпті, вона не добуде. Справді нові тест-ідеї — модель інтерполює бачене й дає типове, а несподівані діри у фічі лишаються за нею. Проєктні конвенції — стиль ваших page object і назви методів без контексту не вгадає. І свіжі факти — API та синтаксис після її knowledge cutoff, звідси вигадані методи бібліотек. Червоний прапорець для інтерв'юера — відповідь «AI усе зробить сам».
Опиши робочий цикл використання AI для тест-артефактів.
Це петля з чотирьох кроків, а не одна кнопка. Крок перший — вкласти в промпт більше, ніж просиш назад: тест-базис, назву техніки, приклад бажаного формату (few-shot); дати контекст дешевше, ніж потім вичищати вигадки. Крок другий — генерація чернетки. Крок третій — рев'ю строго за чек-листом: селектори реальні, перевірки доводять інваріант, покриття зіставлене з AC, немає дублів і галюцинацій; якщо є проблеми — уточнюєш промпт або дороблюєш руками й повертаєшся до генерації. Крок четвертий — виконання: тест реально ганяється й падає з правильної причини, дані валідні. Генерація дешева, рев'ю — ні, і саме воно лишається твоєю відповідальністю.
Що таке «дублі, що вдають покриття», і чому це пастка?
Це коли модель плодить варіації однієї й тієї ж перевірки під різними назвами й видає їх за широкий набір: «невалідний email», «email без @», «неправильний формат пошти» — насправді один клас еквівалентності, а не три незалежні кейси. Широта в переліку є, унікальності немає: три рядки перевіряють те саме. Пастка в тому, що обсяг створює ілюзію ретельності, а реальне покриття не росте. Ловиться це групуванням кейсів за класами еквівалентності — коли зводиш варіації до інваріанта, дублі стають видимі. Тому рев'ю дивиться не на кількість рядків, а на кількість справді різних перевірок.
Три кейси, де видно межу між чернеткою й готовим артефактом: як тест-базис у промпті перетворює банальний вивід на предметний, як рев'ю знешкоджує вигаданий селектор і пусту перевірку в AI-тесті, і як просити тестові дані, щоб вони були відтворювані й безпечні. Скрізь — що дивитися і чому.
Кейс 1. Слабкий промпт проти сильного: чек-лист із критеріїв приймання
Приходить user story на форму промокоду. Спокуса — кинути моделі «напиши тести на промокод» і скопіювати відповідь. Ось що виходить у двох підходах.
Слабкий промпт напиши тести на промокод дає щось таке:
1. Ввести валідний промокод — знижка застосовується
2. Ввести невалідний промокод — помилка
3. Порожнє поле — помилка
4. Застосувати знижку й оформити замовлення
Чотири рядки, самий happy path, жодної специфіки продукту. Тепер годуємо модель тест-базисом — реальними критеріями приймання — і називаємо, що хочемо:
Ось критерії приймання форми промокоду:
- AC1: валідний код дає знижку у відсотках від суми кошика
- AC2: код не діє на товари з розпродажу
- AC3: один код застосовується лише раз на замовлення
- AC4: прострочений код відхиляється з повідомленням
- AC5: код нечутливий до регістру
Згенеруй чек-лист позитивних і негативних перевірок, згрупований за AC.
Окремим блоком дай крайові випадки. Поверни таблицею «AC → перевірка».
Вивід стає предметним, а головне — покриття видно очима:
| Критерій | Перевірка з чек-листа | Покрито |
|---|---|---|
| AC1 | Знижка = відсоток від суми кошика, сума перерахована | так |
| AC2 | Код не зменшує ціну розпродажного товару | так |
| AC3 | Повторне застосування того ж коду відхилено | так |
| AC4 | Прострочений код → повідомлення про закінчення дії | так |
| AC5 | PROMO10 і promo10 дають однаковий результат | так |
Що дивитися і чому:
- Тест-базис прибирає вигадку про фічу. Без критеріїв модель тестувала абстрактний промокод з інтернету; з ними — саме твій, разом із правилом «не діє на розпродаж», якого вона сама не вигадала б.
- Таблиця «AC → перевірка» — це трасування руками. Модель не порахувала покриття, вона його намалювала; але формат сам показує діри — якби рядок AC2 лишився без перевірки, порожня клітинка кинулась би в очі.
- Доменну перевірку все одно дописуєш ти. Якщо бізнес-правило «код не сумується з іншою акцією» не потрапило в AC, модель його не покриє — цей рядок додаєш вручну.
Кейс 2. Рев'ю AI-тесту: вигаданий селектор і пуста перевірка
Модель видала «робочий» Playwright-тест на оформлення замовлення. Виглядає переконливо, комітити не можна:
import { test, expect } from '@playwright/test';
test('оформлення замовлення', async ({ page }) => {
await page.goto('https://shop.example.com/cart');
await page.click('#submit-button'); // такого id у застосунку немає
await expect(page.locator('.result')).toBeVisible(); // «щось видно» — не «замовлення створене»
});
Дві проблеми, обидві типові для AI-виводу. #submit-button модель узяла зі стелі — рядок статистично ймовірний, але кнопка в застосунку інша, тож на прогоні тест упаде «елемент не знайдено». А toBeVisible() на .result пройде, навіть якщо замовлення не створилось: видимість елемента не дорівнює правильному результату. Найковарніше — якщо селектор випадково існує: тоді тест зелений і мовчки не перевіряє нічого.
Мутаційна перевірка ставить діагноз: приберемо створення замовлення на бекенді — тест має почервоніти. Якщо лишається зеленим, він порожній. Після рев'ю той самий сценарій спирається на стабільний локатор і перевіряє реальний інваріант:
import { test, expect } from '@playwright/test';
test('оформлення замовлення створює заявку з номером', async ({ page }) => {
await page.goto('https://shop.example.com/cart');
// рольовий локатор проти реального DOM, а не вигаданий id
await page.getByRole('button', { name: 'Оформити замовлення' }).click();
// перевірка справжнього результату: номер замовлення, а не «щось видно»
await expect(page.getByText(/Замовлення № \d+ прийнято/)).toBeVisible();
});
Що дивитися і чому:
- Кожен селектор із AI-виводу звіряй із живим DOM. Рольові локатори (
getByRole) іdata-testidстабільніші за крихкі#id/.class, але навіть їх модель могла вгадати неправильно — перевірка проти застосунку обов'язкова. - Асерт має падати, коли фіча зламана.
toBeVisible()на випадковому елементі — це не перевірка; перевірка — це очікування конкретного ефекту (номер заявки, зменшення балансу, поява рядка в списку). - Зелений тест без реального асерту гірший за його відсутність. Відсутній тест чесно каже «не покрито»; фальшиво-зелений бреше, що функціонал перевірено, і пропускає баг у прод.
Кейс 3. Тестові дані: відтворювані масові й безпечні крайові
Потрібні дані для перевірки пагінації списку користувачів і окремо — «злі» рядки для поля імені. Просити модель надиктувати десять тисяч рядків у чаті марно: наступний прогін дасть інші значення, а тест на конкретний запис попливе. Просимо код-генератор:
import { faker } from '@faker-js/faker';
faker.seed(42); // фіксований seed → дані відтворювані байт у байт між прогонами
// масові дані: 10 000 користувачів для перевірки пагінації й продуктивності списку
const users = Array.from({ length: 10_000 }, () => ({
email: faker.internet.email(),
name: faker.person.fullName(),
createdAt: faker.date.past(),
}));
Крайові дані — навпаки, найцінніший ручний внесок; окремий промпт «дай список підступних значень для текстового поля» дає готову базу злих рядків:
const nastyNames = [
'', // порожній рядок
' ', // лише пробіл
'a'.repeat(256), // за межею типової довжини
'Ї Й Ґ € 😀 你好', // unicode, емодзі, не-латиниця
"'; DROP TABLE users;--", // SQL-ін'єкція
'<script>alert(1)</script>', // XSS
' Іван ', // пробіли по краях — перевірка trim
];
Що дивитися і чому:
- Детермінованість — через код, не через чат.
fakerіз фіксованим seed відтворює той самий набір, а обсяг міняється однією цифрою; надиктований моделлю список цього не дає. - Крайові значення покривають реальні класи багів. Порожній рядок, гранична довжина, unicode, ін'єкції, пробіли по краях — кожен рядок цілить у свій дефект, а не дублює сусідній.
- Жодного PII чи прод-даних у промпт. Усе вигадане:
fakerгенерує синтетику, тож ніщо реальне не покидає твій контур. Реальні профілі користувачів у чат моделі не йдуть навіть «для реалістичності» — це витік.
Розподіл сил: що доручати моделі
- Тримаю в голові тезу «AI видає чернетку, а не готовий артефакт» і можу пояснити, чому вивід — заготовка, а не істина.
- Знаю, що доручати моделі широту й форму (структура, boilerplate, варіації), а правильність, оракул і реальні селектори лишати за собою.
- Можу пояснити, що таке галюцинація і чому вигадка звучить так само впевнено, як факт.
Тест-кейси і чек-листи з вимог
- Знаю різницю чек-лист vs тест-кейс і що AI краще дає перше (тест-ідеї), стерпно — друге (розписані кроки).
- Розумію, що таке тест-базис і чому без вимоги/AC промпт дає банальний happy path.
- Можу пояснити, чому негативні й крайові перевірки треба просити явно, інакше модель тяжіє до щасливого шляху.
Тестові дані
- Розрізняю три типи даних — реалістичні, крайові (boundary), масові (bulk) — і мету кожного.
- Можу пояснити, чому реалістичні дані краще генерувати кодом з
faker, а не «руками» моделі: детермінованість і відтворюваність. - Знаю, що крайові дані — найцінніший ручний внесок, і вмію попросити «список підступних значень» окремим промптом.
- Твердо пам'ятаю правило: жодних реальних PII чи прод-даних у промпт — лише синтетика.
Генерація автотестів
- Знаю, що AI добре пише boilerplate (скелет тесту, page object, параметризацію) і гарантовано спотикається на селекторах і перевірках.
- Розумію, чому вигаданий селектор (
#submit-button) виглядає робочим, хоч у реальному DOM його немає; звіряю селектори з живим застосунком, а не приймаю на віру. - Можу пояснити, чому зелений тест без реального асерту гірший за відсутність тесту: хибна впевненість.
- Розумію, що таке мутаційна перевірка — зламати фічу й переконатися, що тест червоніє.
Техніки тест-дизайну і покриття
- Можу назвати техніку прямо в промпті (граничні значення, класи еквівалентності, таблиця рішень, переходи станів) і знаю, що це різко піднімає якість виводу.
- Розумію, що таке тест-оракул і чому модель не знає правильного результату без підказки.
- Знаю, що заявлене моделлю покриття — це текст, а не підрахунок; зіставляю кейси з вимогами сам, а таблиця «критерій приймання → кейс» показує прогалини по порожніх рядках.
Воркфлоу і рев'ю
- Можу описати цикл генерація → рев'ю → доробка → виконання, вкладаючи в промпт більше, ніж прошу назад (тест-базис, техніка, few-shot), і пояснити, чому рев'ю — моя відповідальність.
- Розумію, чому виконання — фінальний фільтр: тест не готовий, доки не прогнався й не впав з правильної причини.
- Можу перелічити межі, де AI не можна довіряти: оракул, бізнес-логіка, свіжі факти/API, справді нові ідеї, проєктні конвенції, PII.
Наскільки готовий вивід LLM для тест-артефактів і чому?
Питання
Головна теза про AI-генеровані тест-артефакти?