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

    14 · AI для QA

    Верифікація результатів AI

    Зміст

    У попередній главі Генерація тест-артефактів ми навчилися просити модель писати тест-кейси, автотести й дані. Ця глава — про другу, важливішу половину роботи: як не повірити вигляду. AI-вивід майже завжди читається впевнено, охайно відформатований і компілюється — і саме ця гладкість присипляє пильність. Тест зеленіє, код запускається, баг-репорт звучить професійно — а перевіряє тест порожнечу, код кличе неіснуючий метод, а в репорті — вигаданий заголовок. Верифікація AI-результатів — це навичка не довіряти виводу з першого погляду, і на співбесідах її питають прямо: «як ви перевіряєте те, що згенерував AI?».

    Ця глава працює в парі з попередньою: генерація без верифікації — незавершена робота. Щойно ви реально використовуєте AI для генерації тестів чи коду, ця навичка не опційна — без неї ви чужі помилки під своїм імʼям.

    Чому «виглядає правильно» — це пастка

    Мовна модель оптимізована передбачати правдоподібний наступний токен, а не казати правду. Механіку розібрано в главі Як працюють LLM; тут важливий наслідок: модель однаково впевнено видає і коректну відповідь, і (hallucination) — вигадку, подану як факт. Впевненість тону не корелює з правильністю. Немає внутрішнього індикатора «тут я не знаю»: page.waitForText() вона напише з тією ж інтонацією, що й реальний page.waitForSelector().

    Проблема глибша за саму модель — вона у вашій голові. Чим полірованіший вивід, тим нижча пильність: спрацьовує (automation bias) — схильність довіряти пропозиції системи більше, ніж власній перевірці. Ви очікували робочий код, отримали щось схоже на робочий код — і мозок радо ставить галочку. Для QA це особливо небезпечно, бо весь фах збудований на протилежному рефлексі: не вірити, доки не перевірив.

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

    Типові дефекти AI-згенерованого коду

    Перш ніж говорити «як перевіряти», треба знати, що ламається найчастіше. AI-код має впізнаваний набір дефектів.

    Зелені тести, що нічого не перевіряють. Найпідступніший клас. Тест проходить, метрика росте — а перевірки або немає, або вона тавтологічна. Типове:

    // Виглядає як тест логіну. Насправді не перевіряє нічого.
    test('user can log in', async ({ page }) => {
      await page.goto('/login');
      await page.fill('#email', 'user@example.com');
      await page.fill('#password', 'secret');
      await page.click('button[type=submit]');
      // ← тут мав бути expect. Його немає. Тест зелений завжди.
    });

    Той самий дефект у витонченішій формі — забутий await перед web-first Playwright або перевірка, яка істинна за побудовою:

    await expect(page.locator('.title')).toBeVisible(); // забули await → проміс не дочекано, помилка проковтнута
    expect(true).toBeTruthy();                          // тавтологія: не впаде ніколи

    Вигадані API й селектори. Модель компонує імена методів зі шматків, які бачила, і легко вигадує неіснуючі: page.waitForText(), cy.getByRole() (у Cypress такого немає), опції конфіга, яких немає в документації. Так само з : getByRole('button', { name: 'Зберегти' }) виглядає бездоганно, але якщо в реальному DOM цієї ролі чи назви немає — селектор не знайде нічого. Модель не бачила вашої сторінки; вона вгадала розмітку.

    Поверхневі перевірки. Покрито лише . Перевіряється присутність елемента, а не його коректність: що кнопка є — але не що вона робить правильну дію; що прийшов 200 — але не що в тілі відповіді правильні дані.

    Застарілі патерни. waitForTimeout(3000) замість web-first очікування, виклики застарілих API, стиль із туторіалів пʼятирічної давнини, які потрапили в тренувальні дані.

    Три опори верифікації

    Перевірка AI-виводу тримається на трьох діях: прочитати як рев'юер, виконати як реальність, звірити факти з першоджерелом. Жодна поодинці не достатня.

    Ні

    Так

    AI згенерував

    Рев'ю: прочитати критично

    Виконання: запустити й зламати навмисне

    Факти: звірити з першоджерелом

    Проходить DoD?

    Твій коміт, твоя відповідальність

    Ні

    Так

    AI згенерував

    Рев'ю: прочитати критично

    Виконання: запустити й зламати навмисне

    Факти: звірити з першоджерелом

    Проходить DoD?

    Твій коміт, твоя відповідальність

    Рев'ю виводу як навичка

    Читайте AI-вивід так, як ревʼюили б джуна — тільки скептичніше. У джуна є контекст задачі й совість сказати «я тут не впевнений»; у моделі немає ні того, ні того. Це та сама навичка, що й статичне рев'ю коду в класичному QA, лише обʼєкт — машинний вивід.

    Головне питання до тесту: що станеться, якщо фіча зламається — цей тест почервоніє? Подумки «мутуйте» застосунок: приберіть кнопку, інвертуйте валідацію, поверніть неправильні дані — чи впіймає це тест? Якщо ні — тест декоративний. Друге питання: чого цей тест НЕ ловить? happy path без негативних перевірок, відсутні , перевірка присутності замість перевірки значення.

    Для не-кодового виводу (тест-кейси з вимог, аналіз багів) рев'ю таке саме: чи всі кроки відтворювані, чи очікуваний результат — це справді інваріант вимоги, а не переказ дії, чи не проґавлені негативні сценарії.

    Виконання як перевірка

    Найдешевша перевірка реальністю — просто запустити. Компілюється? Селектор резолвиться в живому DOM? Тест доходить до кінця? Це відсіює вигадані API й селектори за секунди — те, чого рев'ю очима може не помітити.

    Але виконання має межу, і це найважливіший пункт глави: зелений прогін не доводить, що тест щось перевіряє. Порожній тест із прикладу вище зелений завжди. Тому виконання доповнюють однією дією — зламати навмисне. Змініть очікуване значення на завідомо неправильне, закоментуйте фічу в застосунку, підмініть відповідь. Якщо тест лишається зеленим — він фальшивий. Справжній доказ якості тесту не в тому, що він проходить, а в тому, що він червоніє, коли має.

    // Перевірка тесту: тимчасово ламаємо очікування
    await expect(page.locator('.balance')).toHaveText('1000'); // було
    await expect(page.locator('.balance')).toHaveText('НЕПРАВИЛЬНО'); // тест мусить впасти

    Якщо після цієї підміни тест усе одно зелений — асерт не працює (забутий await, тавтологічне очікування або асерт, до якого виконання взагалі не доходить), і зеленому оригіналу гріш ціна.

    Верифікація фактів

    Для тверджень, а не коду, працює інше правило: звіряй із першоджерелом, а не з тією ж моделлю. Коли AI називає номер версії, назву HTTP-заголовка, сигнатуру методу чи — це рівно те, що модель галюцинує найохочіше. Перевіряйте проти канонічного джерела: офіційна документація інструмента, специфікація, реальний код застосунку.

    Критична пастка: не перепитуйте ту саму модель «ти впевнений?». Вона не має нового джерела — тільки той самий розподіл імовірностей і той самий bias. Часто вона або впевнено підтвердить вигадку, або з тією ж упевненістю розвернеться на 180° без жодної нової інформації. І те, і те — шум. Реальна перевірка приходить лише ззовні: відкрити доку, запустити код, глянути в DevTools.

    Приклад. Модель радить expect(page).toHaveText('Готово'). Виглядає розумно. Але за документацією Playwright toHaveText існує для локатора, не для page. Правильно — expect(page.locator('...')).toHaveText(...). Знайти це можна лише в доці, а не перепитуванням моделі.

    Definition of Done для AI-виводу

    Верифікація стає повторюваною, коли є чек-лист «готово». Для AI-згенерованого коду він не мʼякший за ваш звичайний DoD — він той самий:

    • Компілюється і запускається без вигаданих API, опцій, імпортів.
    • Селектори резолвляться в реальному DOM (див. DOM і селектори).
    • Тест червоніє, коли фічу зламано (перевірено навмисною поломкою).
    • Покрито не лише happy path: є негативні й граничні перевірки з вимоги.
    • Факти (версії, заголовки, коди, сигнатури) звірені з першоджерелом.
    • Немає протікання секретів чи PII у код або в .
    • Відповідає конвенціям проєкту, а не абстрактному стилю з інтернету.

    Якщо (JSON за схемою) генерується для інструментів — його валідують проти схеми програмно, не очима; про це докладніше в главі Tool use і function calling. А коли перевіряти доводиться масово й регулярно — це вже територія Evals та LLM-as-judge і Тестування AI-застосунків.

    Відповідальність — твоя

    Останнє й найважливіше. У коміті стоїть ваше імʼя, не імʼя моделі. «AI так написав» — не аргумент ні на код-рев'ю, ні на пост-мортемі після інциденту. Модель не несе відповідальності, не памʼятає контексту й не постане перед командою — усе це лягає на людину, яка натиснула «закомітити».

    Найздоровіша ментальна модель: AI — це дуже швидкий джун, чию роботу ви апрувите своїм підписом. Швидкість він дає вам справжню; відповідальність за якість лишає вам повністю. Верифікація — це і є та точка, де ви цей підпис ставите свідомо.

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

    • Тест зелений — виглядає як робоче покриття, а насправді асерт відсутній або забутий await проковтнув помилку: тест не впаде ніколи.
    • Код компілюється — виглядає як коректний, а насправді кличе метод, що існує лише «у світі моделі» (page.waitForText, cy.getByRole), і впаде на першому реальному виклику.
    • Модель упевнено назвала версію/заголовок/код — виглядає як факт, а насправді галюцинація, яку видно лише при звірці з документацією.
    • «Перепитав модель — вона підтвердила» — виглядає як верифікація, а насправді те саме джерело з тим самим bias; нової інформації нуль.
    • Селектор getByRole('button', { name: '…' }) — виглядає бездоганно, а насправді елемента з такою роллю чи назвою в DOM немає, бо модель не бачила сторінки.
    • AI покрив happy path — виглядає як готовий набір тестів, а насправді негативні й граничні сценарії відсутні, і реальні баги пройдуть повз.

    Підсумок

    • Гладкість не дорівнює правильності: охайний, впевнений, скомпільований вивід нічого не гарантує.
    • Зелений тест — не доказ; доказ — що тест червоніє, коли фіча ламається. Ламайте навмисне.
    • Виконання ловить вигадані API й селектори, але не порожні перевірки — потрібні всі три опори: рев'ю, виконання, факти.
    • Факти звіряй із першоджерелом, а не перепитуванням тієї ж моделі.
    • DoD для AI-коду дорівнює твоєму звичайному DoD; відповідальність за вивід — на тобі, не на моделі.

    Можливі питання

    • «Як ви перевіряєте код, згенерований AI?» — інтервʼюер хоче почути, що зелений прогін вас не переконує: ви читаєте вивід критично, ламаєте тест навмисне, звіряєте API з документацією. Відповідь «запускаю, і якщо зелений — ок» — червоний .
    • «AI написав тест, він проходить. Цього достатньо?» — пастка на розуміння різниці «проходить» vs «перевіряє». Сильна відповідь: ні, спершу переконаюся, що тест падає, коли фічу зламано.
    • «Був випадок, коли AI вас підвів?» — поведінкове питання; готуйте конкретну історію: вигаданий метод, селектор під неіснуючий елемент, галюцинований заголовок — і як ви це впіймали.
    • «Хто відповідає за баг у AI-згенерованому коді, що доїхав у прод?» — перевірка зрілості. Правильна рамка: той, хто закомітив; AI не суб'єкт відповідальності.

    На що дивиться інтервʼюер: чи трактуєте ви AI-вивід як чернетку на рев'ю, а не як істину; чи усвідомлюєте упередження автоматизації; чи маєте конкретний, повторюваний спосіб перевірки, а не «на око».

    Джерела

    Чому «виглядає правильно» — це пастка

    • ISTQB CT-GenAI Syllabus v1.1 — найкоротша форма тези в каноні: текст статистично правдоподібний, але But plausible is not necessarily correct.
    • ISTQB CT-AI Syllabus v2.0 — матеріальна підстава: моделі схильні до впевнених, але неправильних передбачень, і це наслідок даних, а не рідкісний збій.
    • Brown et al. — Language Models are Few-Shot Learners (arXiv:2005.14165) — виміряний бік проблеми в голові читача: люди важко відрізняють згенерований текст від написаного людиною.
    • Claude Code Docs — Best practices for Claude Code — той самий автоматизм у дозволах: після десятого підтвердження ви вже не рев'юїте, а клікаєте.

    Типові дефекти AI-згенерованого коду

    • Playwright — Writing tests — означення тесту (дії плюс асерти про стан) і механіка забутого await: асинхронні матчери його потребують, загальні — ні.
    • Playwright — Assertions — канонічний перелік справжніх асертів і поділ на ретрайні та неретрайні, через які тест і стає .
    • Playwright — Best Practices — чому waitForTimeout є застарілим патерном: ставка на web-first перевірки й замість ручних пауз.
    • Claude Code Docs — Best practices for Claude Codetrust-then-verify gap: правдоподібна на вигляд реалізація, яка не покриває .

    Три опори верифікації

    • Claude Code Docs — Best practices for Claude Code — чим саме буває перевірка (, лінтер, скрипт-дифф, ), правило If you can't verify it, don't ship it і вимога просити доказ, а не заяву про успіх.
    • ISTQB CT-GenAI Syllabus v1.1 — канонічні способи виявлення окремо під кожен клас дефекту (перехресна звірка, логічна валідація, виконання виводу) і глибина перевірки пропорційно .
    • Playwright — Writing tests — межа виконання дослівно: воно ловить вигадані API за секунди, але не порожні перевірки; там же — що toHaveText існує для локатора, а не для page.
    • ISTQB CTFL Syllabus v4.0 — рев'ю як структурований, але гнучкий процес із заданими цілями й : та сама дисципліна, тільки обʼєкт машинний.
    • ISTQB CT-AI Syllabus v2.0 — чому «перепитати ту саму модель» не є перевіркою: другий оцінювач на тій самій технології відтворює ті самі упередження й помилки.

    Definition of Done для AI-виводу

    • Claude Code Docs — Best practices for Claude Code — найсильніша модальність доки під цим чек-листом: Always provide verification (tests, scripts, screenshots). If you can't verify it, don't ship it.
    • Claude Code Docs — Run Claude Code programmatically (headless) — межа програмної валідації: схему можна закріпити на рівні API, але format трактується як анотація й не примушується.
    • Playwright — Best Practices — орієнтир для пункту про конвенції та стабільні локатори, проти якого рев'юють згенерований тест.
    • ISTQB CT-GenAI Syllabus v1.1 — гейт із модальністю MUST і прив'язкою глибини перевірки до оціненого рівня ризику.

    Відповідальність — твоя

    • ISTQB CT-GenAI Syllabus v1.1 — людська оцінка названа необхідною без пом'якшень: Human evaluation is essential for ensuring quality and accuracy of GenAI-powered test tasks.
    • Claude Code Docs — Best practices for Claude Code — зворотний бік: без зовнішньої перевірки єдиний сигнал зупинки — «схоже на готове», і петлею верифікації стаєте ви.

    Пояснення

    «Поясни» працює з власним API-ключем Anthropic: запит іде з вашого браузера прямо до Anthropic.

    Свій API-ключ (BYOK)

    Вставте власний ключ Anthropic — пояснення працюватиме на реальній моделі. Ключ зберігається лише у вашому браузері (localStorage), нікуди не надсилається, крім api.anthropic.com, і не логується.