Таблиці рішень
Зміст
Класи еквівалентності й межі чудово працюють, поки поле одне: сума, дата, довжина рядка. Але реальна бізнес-логіка рідко залежить від одного поля. Знижка рахується з суми замовлення, статусу підписки і промокоду одночасно — і баг живе не в кожній умові окремо, а в їх комбінації: промокод працює, преміум працює, а разом вони чомусь дають подвійну знижку. Поодинокі перевірки полів такі баги не ловлять у принципі, бо кожна умова сама по собі справна.
Таблиця рішень (decision table) — техніка саме для цього: вона змушує виписати всі умови, всі дії та всі їх комбінації в одну компактну структуру, де прогалини й суперечності видно очима ще до першого тесту. На співбесідах це одна з найчастіших тем тест-дизайну: «побудуйте таблицю для знижки», «скільки тестів потрібно для трьох умов», «що таке don't care» — класика для рівня junior і вище.
Коли таблиця, а коли ні
Сигнал, що потрібна таблиця рішень, — формулювання вимог у стилі «якщо… і… то…», особливо коли таких речень кілька і вони посилаються на одні й ті самі поля з різних кінців сторінки. Типові кандидати: розрахунок знижок і тарифів, права доступу (роль × стан ресурсу), валідація заявки за кількома критеріями, маршрутизація замовлення.
Межі техніки теж варто знати, бо про них питають:
| Ситуація | Що взяти |
|---|---|
| Результат залежить від комбінації незалежних умов «тут і зараз» | Таблиця рішень |
| Результат залежить від історії: що було до цього, у якому стані обʼєкт | Переходи станів |
| Одне поле з діапазонами значень | Класи еквівалентності + межі |
| Багато параметрів без жорстких правил між ними (конфігурації, фільтри) | Попарне тестування |
Ключова відмінність від переходів станів: таблиця рішень — «фотографія» логіки в один момент часу. Якщо та сама комбінація умов дає різний результат залежно від того, що сталося раніше, — це вже стан, і таблиця тут збреше.
Структура: умови, дії, правила
Таблиця складається з трьох частин:
- Умови (conditions) — рядки у верхній частині: те, від чого залежить поведінка. У базовій, обмеженій формі (limited-entry) кожна умова бінарна: істина (T) або хиба (F).
- Дії (actions) — рядки в нижній частині: те, що система робить. Позначка X у клітинці — «дія виконується».
- Правила (rules) — колонки: кожна колонка задає одну комбінацію умов і дії, які їй відповідають. Правило читається зверху вниз: «якщо умови такі — роби ось це».
Розберемо на живій вимозі. Специфікація інтернет-магазину каже:
Доставка безкоштовна для замовлень від 1000 грн. Власникам преміум-підписки доставка безкоштовна завжди. В інших випадках діє тариф 80 грн. Преміум-підписка доступна лише залогіненим користувачам.
Виписуємо умови й дії:
- У1: користувач залогінений
- У2: у користувача преміум-підписка
- У3: сума замовлення від 1000 грн
- Д1: доставка безкоштовна
- Д2: тариф 80 грн
Зверни увагу: «сума замовлення» — не бінарна умова, а діапазон. У таблицю вона потрапляє вже як предикат «сума ≥ 1000», тобто після розбиття на класи еквівалентності. Конкретні значення для тестів (999, 1000) потім дадуть граничні значення — техніки працюють разом, а не замість одна одної.
Повна таблиця: 2^n правил
Кожна бінарна умова подвоює кількість комбінацій, тож повна таблиця для n умов має 2^n правил. Для наших трьох умов — 8 колонок:
| П1 | П2 | П3 | П4 | П5 | П6 | П7 | П8 | |
|---|---|---|---|---|---|---|---|---|
| У1: залогінений | T | T | T | T | F | F | F | F |
| У2: преміум | T | T | F | F | T | T | F | F |
| У3: сума ≥ 1000 | T | F | T | F | T | F | T | F |
| Д1: безкоштовна доставка | X | X | X | ? | ? | X | ||
| Д2: тариф 80 грн | X | ? | ? | X |
Повна таблиця — це чернетка, а не фінальний артефакт. Її цінність у систематичності: жодна комбінація не загубиться, бо ти механічно перебрав усі. Саме на цьому кроці зазвичай випливають знахідки — наприклад, П5 і П6: гість із преміум-підпискою. Специфікація каже, що так не буває, — і чесний знак питання в чернетці кращий за мовчазне припущення.
Зростання 2^n — головне обмеження техніки: 5 умов — це 32 колонки, 10 — уже 1024. Тому повну таблицю будують для добірки звʼязаних умов (зазвичай 3–5), а не для всієї фічі одразу. Якщо умов справді багато й вони слабо повʼязані — це сигнал подивитись у бік попарного тестування.
Згортання: don't care і неможливі комбінації
Повну таблицю стискають двома інструментами.
Неможливі комбінації прибираємо. П5 і П6 (гість із преміумом) за бізнес-правилами не існують: підписка вимагає акаунта. Такі колонки викреслюють із таблиці — але не з голови: якщо «неможлива» комбінація все ж може прийти ззовні (прямий запит до API в обхід UI, розсинхрон даних), система має обробити її гідно, і це вже негативна перевірка. Про такі сценарії докладніше в розділі про API-тестування.
Don't care («байдуже», позначається «—») — випадок, коли значення умови не впливає на результат. Подивись на П1 і П2: якщо преміум є, доставка безкоштовна незалежно від суми. Дві колонки зливаються в одну з «—» у рядку суми. Так само П3 і П7: якщо преміуму немає, а сума достатня, — байдуже, залогінений користувач чи гість.
Згорнута таблиця:
| К1 | К2 | К3 | |
|---|---|---|---|
| У1: залогінений | T | — | — |
| У2: преміум | T | F | F |
| У3: сума ≥ 1000 | — | T | F |
| Дія | безкоштовна | безкоштовна | тариф 80 грн |
Вісім правил згорнулися до трьох — без втрати покриття логіки, бо кожне з восьми вихідних правил або неможливе, або накрите однією з трьох колонок.
Важливий нюанс, який відрізняє акуратного тестувальника: «—» — це твердження «результат однаковий за обох значень», а не дозвіл не думати. Кожен don't care має підтверджуватися специфікацією або перевіркою. Якщо є сумнів — залиш обидві колонки: підозріло «зайва» комбінація часто виявляється або багом, або дірою у вимогах.
Від правила до тест-кейсу
Мінімальне покриття таблиці рішень — один тест-кейс на кожне правило (колонку) згорнутої таблиці. Покриття рахується просто: перевірені колонки поділити на всі колонки. Три правила — три кейси мінімум.
Правило задає логіку кейсу, але не конкретні дані. Значення підбираємо іншими техніками:
- К1: преміум-користувач, сума — будь-яка з валідного класу, наприклад 200 грн. Очікування: доставка 0 грн.
- К2: преміум відсутній, сума рівно 1000 грн — беремо граничне значення, бо саме на межі живуть off-by-one баги. Для don't care у рядку «залогінений» можна взяти гостя — так кейс заодно зачепить менш очевидну гілку.
- К3: без преміуму, сума 999 грн — друга точка тієї ж межі. Очікування: тариф 80 грн.
Таблиця природно лягає в параметризований автотест: колонки стають елементами масиву даних, а тест один.
const rules = [
{ name: 'преміум: безкоштовно незалежно від суми', premium: true, total: 200, shipping: 0 },
{ name: 'сума 1000: безкоштовно без преміуму', premium: false, total: 1000, shipping: 0 },
{ name: 'без пільг: стандартний тариф', premium: false, total: 999, shipping: 80 },
];
for (const rule of rules) {
test(`доставка — ${rule.name}`, async ({ page }) => {
await seedCart(page, { premium: rule.premium, total: rule.total });
await expect(page.getByTestId('shipping-cost')).toHaveText(String(rule.shipping));
});
}
Назва кожного тесту описує правило, а не кроки — впав тест К2, і зі звіту одразу видно, яка комбінація зламалася. Додалась умова у вимогах — додаєш колонку в таблицю й рядок у масив, не переписуючи тест.
Cause-effect: звідки беруться умови
Найважчий крок техніки — не побудова таблиці, а видобування умов із розлогого тексту вимог. Тут допомагає причинно-наслідковий граф (cause-effect graph) — класична техніка, яку популяризував Гленфорд Маєрс у «The Art of Software Testing»: причини (входи й умови) зʼєднуються з наслідками (діями системи) логічними звʼязками І/АБО/НЕ, а обмеження фіксують залежності між самими причинами — наприклад, «преміум вимагає залогіненості».
Граф і таблиця — два подання тієї самої логіки: граф зручно малювати, поки розплутуєш текст вимог, а таблицю — заповнювати й перевіряти на повноту. Класичний воркфлоу: прочитав вимоги → виписав причини й наслідки → звʼязав логікою → переніс причини в рядки умов, наслідки в рядки дій → перебрав комбінації. На практиці граф часто пропускають і йдуть одразу в таблицю — це нормально; але коли вимоги заплутані й суперечливі, проміжний граф рятує: суперечність двох речень специфікації на графі видно як конфлікт звʼязків.
Побічний ефект обох технік — рев'ю вимог безкоштовно. Заповнюючи таблицю, ти ставиш аналітику питання, які без неї ніхто б не поставив: «а що, як промокод і преміум одночасно?», «а гість із сумою 1000?». Половина цінності техніки — дефекти специфікації, знайдені до написання коду; це прямий прояв принципу раннього тестування з розділу основ.
Типові помилки
- Виглядає як «три умови — три тести: перевірю кожну окремо», а насправді логіка живе в комбінаціях: кожна умова окремо може працювати, а разом — ні. Мінімум — тест на кожне правило таблиці, а не на кожну умову.
- Виглядає як «don't care — можна підставити будь-що й забути», а насправді це твердження, що результат однаковий за обох значень, — і його треба підтвердити специфікацією. Необґрунтований «—» ховає рівно ті баги, заради яких таблицю будували.
- Виглядає як «неможливу комбінацію викреслив — і по всьому», а насправді «неможливе» іноді приходить: прямим викликом API, багом сусідньої системи, гонкою двох запитів. Викреслити з таблиці — так; викреслити з голови — ні.
- Виглядає як «дві колонки з однаковими умовами й різними діями — я помилився в таблиці», а насправді це часто суперечність у самих вимогах: два речення специфікації командують різне. Така знахідка цінніша за десяток прогнаних тестів.
- Виглядає як «сума замовлення — одна умова», а насправді це діапазон, який спершу треба розбити на класи еквівалентності; у таблицю заходить уже готовий предикат. Якщо запхати в одну умову кілька порогів — таблиця перестане бути бінарною й розповзеться.
Підсумок
- Таблиця рішень — техніка для логіки, де результат визначає комбінація умов, а не кожна умова окремо; сигнал — вимоги у стилі «якщо… і… то…».
- Структура: умови й дії — рядки, правила — колонки; повна таблиця для n бінарних умов має 2^n правил.
- Згортання — через don't care (умова не впливає на результат — підтверджено!) і викреслення неможливих комбінацій; покриття логіки при цьому не втрачається.
- Мінімальне покриття — один тест-кейс на кожне правило згорнутої таблиці; конкретні дані для кейсу дають класи еквівалентності та граничні значення.
- Таблиця — ще й інструмент рев'ю вимог: суперечності, прогалини й «а що, як?» видно на етапі заповнення, до першого запуску тесту.
Що питають на співбесіді
- «Скільки тестів потрібно для трьох (чотирьох, пʼяти) умов?» Пастка на розуміння 2^n: повна таблиця — 8 (16, 32) правил, але відповідь сильного кандидата продовжується словами «…а після згортання неможливих комбінацій і don't care — менше; мінімум один кейс на правило згорнутої таблиці». Інтервʼюер дивиться, чи не зупинишся ти на механічному 2^n.
- «Що таке don't care і коли ним можна користуватися?» Перевіряють, чи розумієш різницю між «байдуже» як доведеним фактом і як лінню. Згадай, що don't care вимагає підтвердження специфікацією.
- «Чим таблиця рішень відрізняється від класів еквівалентності? А від переходів станів?» Дивляться на розуміння меж технік: класи — про діапазони одного параметра, таблиця — про комбінації умов, стани — про залежність від історії.
- «Побудуйте таблицю рішень для знижки/тарифу/доступу» — практична задача, найчастіший формат. Інтервʼюер оцінює процес: чи випишеш умови й дії з тексту, чи помітиш неможливі комбінації, чи поставиш уточнювальні питання про суперечності замість мовчки щось припустити. Розгорнутий розбір таких задач — у главі про класичні задачі співбесід.
- «Що робити, якщо умов десять?» Перевірка на здоровий глузд: 1024 колонки ніхто не будує — розбити логіку на незалежні таблиці, згорнути, а для слабозвʼязаних параметрів перейти до попарного тестування.
Джерела
- ISTQB CTFL Syllabus v4.0 — розділ 4.2.3 «Decision Table Testing»: ця глава покриває його повністю, плюс cause-effect graphing поза силабусом.
- Глосарій ISTQB — канонічні означення термінів decision table testing, cause-effect graphing, coverage item.
- ISO/IEC/IEEE 29119-4 «Software and systems engineering — Software testing — Part 4: Test techniques» — формальний опис decision table testing і cause-effect graphing як специфікаційних технік.
- Glenford Myers, Corey Sandler, Tom Badgett — «The Art of Software Testing» (3rd ed., Wiley, 2011) — класичний розгорнутий опис cause-effect graphing із повною нотацією обмежень.
Що таке таблиця рішень і для яких задач вона призначена?
Таблиця рішень (decision table) — техніка тест-дизайну для логіки, де результат визначає комбінація умов, а не кожна умова окремо. Вона змушує виписати всі умови, всі дії та всі їх комбінації в одну структуру, де прогалини й суперечності видно ще до першого тесту. Потреба виникає, бо баги комбінаційної логіки не ловляться поодинокими перевірками полів: промокод працює, преміум працює, а разом дають подвійну знижку — кожна умова окремо справна. Сигнал, що техніка доречна, — вимоги у стилі «якщо… і… то…», особливо коли таких речень кілька і вони посилаються на ті самі поля. Типові кандидати: розрахунок знижок і тарифів, права доступу, валідація заявки за кількома критеріями, маршрутизація замовлення.
З яких частин складається таблиця рішень і як її читати?
Три частини: умови, дії, правила. Умови (conditions) — рядки верхньої частини: те, від чого залежить поведінка; у базовій limited-entry формі кожна умова бінарна — T або F. Дії (actions) — рядки нижньої частини: те, що система робить; X у клітинці означає «дія виконується». Правила (rules) — колонки: кожна задає одну комбінацію умов і відповідні їй дії. Правило читається зверху вниз: «якщо умови такі — роби ось це».
Скільки правил у повній таблиці для трьох умов? А для пʼяти?
Кожна бінарна умова подвоює кількість комбінацій, тож повна таблиця для n умов має 2^n правил: три умови — 8, пʼять — 32, десять — уже 1024. Але сильна відповідь на цьому не зупиняється: повна таблиця — чернетка, а не план тестування. Після викреслення неможливих комбінацій і згортання через don't care правил стає менше, і мінімум — один тест-кейс на кожне правило згорнутої таблиці. Інтервʼюер цим питанням якраз перевіряє, чи не зупинишся ти на механічному 2^n.
Чому не можна покрити три умови трьома тестами — по одному на кожну умову?
Бо логіка живе в комбінаціях: кожна умова окремо може працювати бездоганно, а їх поєднання — ні. Тест «перевірю преміум», тест «перевірю суму» й тест «перевірю логін» не зачеплять випадок «преміум плюс велика сума одночасно», а баг найчастіше саме там. Мінімальне покриття — тест на кожне правило таблиці, тобто на кожну комбінацію, що лишилася після згортання, а не на кожну умову. Це і є головна причина існування техніки.
Чим таблиця рішень відрізняється від класів еквівалентності — це конкурентні техніки?
Ні, вони працюють разом, а не замість одна одної. Класи еквівалентності — про діапазони значень одного параметра; таблиця рішень — про комбінації кількох умов. Умова-діапазон на кшталт «сума замовлення» заходить у таблицю вже як предикат «сума ≥ 1000», тобто після розбиття на класи. А коли правило згорнутої таблиці перетворюється на тест-кейс, конкретні значення дають граничні значення: для межі 1000 — точки 999 і 1000. Правило задає логіку кейсу, класи й межі — дані.
Чим таблиця рішень відрізняється від переходів станів?
Таблиця рішень — «фотографія» логіки в один момент часу: результат залежить від комбінації умов «тут і зараз». Переходи станів — про історію: що було до цього, у якому стані обʼєкт. Ключовий тест на розрізнення: якщо та сама комбінація умов дає різний результат залежно від того, що сталося раніше, — це вже стан, і таблиця тут збреше. На співбесіді цю межу питають прямо, разом із межею проти класів еквівалентності.
Як у бінарну таблицю потрапляє умова на кшталт «сума замовлення»?
«Сума замовлення» — не бінарна умова, а діапазон, тож напряму в limited-entry таблицю вона не заходить. Спочатку діапазон розбивають на класи еквівалентності, і в таблицю потрапляє готовий предикат: «сума ≥ 1000» з відповідями T/F. Якщо запхати в одну умову кілька порогів, таблиця перестане бути бінарною й розповзеться. Конкретні значення для тестів (999, 1000) потім дадуть граничні значення — off-by-one баги живуть саме на межі.
Що таке don't care і коли ним можна користуватися?
Don't care («байдуже», позначається «—») — випадок, коли значення умови не впливає на результат: якщо преміум є, доставка безкоштовна незалежно від суми, і дві колонки зливаються в одну з «—» у рядку суми. Головний нюанс: «—» — це твердження «результат однаковий за обох значень», а не дозвіл не думати. Кожен don't care має підтверджуватися специфікацією або перевіркою. Якщо є сумнів — залиш обидві колонки: підозріло «зайва» комбінація часто виявляється багом або дірою у вимогах. Саме цю різницю між «доведено» і «полінувався» перевіряють на співбесіді.
Що робити з комбінаціями, які специфікація оголошує неможливими?
З таблиці — викреслити: колонки на кшталт «гість із преміум-підпискою» за бізнес-правилами не існують, і тримати їх у згорнутій таблиці немає сенсу. Але викреслити з таблиці не означає викреслити з голови: «неможливе» іноді приходить ззовні — прямим запитом до API в обхід UI, багом сусідньої системи, розсинхроном даних, гонкою двох запитів. Система має обробити таку комбінацію гідно, і це вже негативна перевірка. Акуратний тестувальник спершу ставить чесний знак питання в чернетці, а не мовчки припускає.
У заповненій таблиці дві колонки з однаковими умовами, але різними діями. Що це означає?
Найчастіше це не помилка заповнення, а суперечність у самих вимогах: два речення специфікації командують різне для тієї самої комбінації умов. Така знахідка цінніша за десяток прогнаних тестів, бо це дефект, спійманий до написання коду. Правильна реакція — не «виправити» таблицю на власний розсуд, а піти до аналітика з конкретним питанням: «для цієї комбінації пункт A каже одне, пункт B — інше; як має бути?». Це прояв того, що таблиця — ще й інструмент рев'ю вимог.
Як від правила таблиці перейти до конкретного тест-кейсу і як рахується покриття?
Мінімальне покриття — один тест-кейс на кожне правило (колонку) згорнутої таблиці; покриття рахується як перевірені колонки поділити на всі колонки. Правило задає логіку кейсу, але не конкретні дані — значення підбирають іншими техніками: з валідного класу еквівалентності, а на межах — граничні значення (сума рівно 1000 і 999 для предиката «сума ≥ 1000»). Для don't care у кейсі можна свідомо взяти менш очевидну гілку — наприклад, гостя замість залогіненого, — щоб кейс заодно зачепив її.
Як таблиця рішень лягає в автоматизацію?
Природно — у параметризований тест: колонки згорнутої таблиці стають елементами масиву даних, а тест один. Назва кожного тесту описує правило, а не кроки: впав тест — і зі звіту одразу видно, яка комбінація зламалася. Додалась умова у вимогах — додаєш колонку в таблицю й рядок у масив, не переписуючи сам тест. Це робить набір тестів дзеркалом таблиці: розсинхрон між вимогами й тестами видно очима.
Що робити, якщо умов десять?
Це перевірка на здоровий глузд: 2^10 — 1024 колонки, і таку таблицю ніхто не будує. Правильна стратегія — розбити логіку на кілька незалежних таблиць для добірок звʼязаних умов (зазвичай 3–5) і кожну згорнути. Якщо умов багато й вони слабо повʼязані між собою — без жорстких правил, як конфігурації чи фільтри, — це сигнал перейти до попарного тестування. Сама потреба в такій розбивці часто підказує, що фіча склеєна з кількох незалежних шматків логіки.
Що таке причинно-наслідковий граф і навіщо він, якщо є таблиця?
Причинно-наслідковий граф (cause-effect graph) — класична техніка, яку популяризував Гленфорд Маєрс у «The Art of Software Testing»: причини (входи й умови) зʼєднуються з наслідками (діями системи) логічними звʼязками І/АБО/НЕ, а обмеження фіксують залежності між самими причинами — наприклад, «преміум вимагає залогіненості». Граф і таблиця — два подання тієї самої логіки: граф зручно малювати, поки розплутуєш текст вимог, таблицю — заповнювати й перевіряти на повноту. На практиці граф часто пропускають і йдуть одразу в таблицю — це нормально. Але коли вимоги заплутані й суперечливі, проміжний граф рятує: суперечність двох речень специфікації на ньому видно як конфлікт звʼязків.
Яку користь дає таблиця рішень ще до запуску першого тесту?
Рев'ю вимог безкоштовно. Заповнюючи таблицю, ти механічно перебираєш усі комбінації й змушений ставити аналітику питання, які без таблиці ніхто б не поставив: «а що, як промокод і преміум одночасно?», «а гість із сумою 1000?». Половина цінності техніки — дефекти специфікації, знайдені до написання коду: прогалини, суперечності, неможливі комбінації, про які вимоги мовчать. Це прямий прояв принципу раннього тестування: найдешевший баг — той, що не доїхав до коду.
Три кейси з робочого життя: побудова таблиці рішень із «сирої» вимоги про знижки (з дірою, яку таблиця витягує на світло), переклад згорнутої таблиці в параметризований Playwright-тест і негативна перевірка «неможливої» комбінації через прямий API-запит. Скрізь — що дивитися і чому.
Кейс 1. Від тексту вимоги до згорнутої таблиці
Аналітик приносить вимогу — типовий формат «якщо… і… то…», розкиданий по кількох реченнях:
Замовлення від 2000 грн отримує знижку 10%. Учасники програми лояльності мають знижку 15%; знижки за суму та лояльність не сумуються — діє більша. Промокод SALE дає знижку 20% і не поєднується з іншими знижками.
Виписуємо умови й дії. «Сума замовлення» — діапазон, тож у таблицю вона заходить уже предикатом:
- У1: сума ≥ 2000
- У2: учасник програми лояльності
- У3: застосовано промокод SALE
- Дії: знижка 0% / 10% / 15% / 20%
Три бінарні умови — повна таблиця на 2^3 = 8 правил:
| П1 | П2 | П3 | П4 | П5 | П6 | П7 | П8 | |
|---|---|---|---|---|---|---|---|---|
| У1: сума ≥ 2000 | T | T | T | T | F | F | F | F |
| У2: лояльність | T | T | F | F | T | T | F | F |
| У3: промокод SALE | T | F | T | F | T | F | T | F |
| Знижка | ? | 15% | ? | 10% | ? | 15% | 20% | 0% |
Що дивитися і чому:
- Три знаки питання — головна знахідка кейсу. «Не поєднується з іншими знижками» читається двояко: промокод перекриває інші знижки чи не застосовується, коли вони є? П1, П3, П5 — усі комбінації, де промокод зустрічається з іншою знижкою, — вимогою не визначені. Це питання до аналітика, а не місце для мовчазного припущення.
- П2 і П6 визначені чітко — для пари «сума проти лояльності» правило «діє більша» у вимозі є. Порівняйте: одна пара знижок описана, друга — ні. Саме такі перекоси й витягує механічний перебір комбінацій.
- Знак питання в чернетці — нормальний стан. Повна таблиця і є інструментом пошуку таких дір; чесний «?» кращий за впевнену вигадку.
Аналітик відповідає: «промокод перекриває решту — діє найбільша знижка». Тепер П1, П3, П5 дають 20%, і таблиця згортається: якщо У3 = T, знижка 20% незалежно від решти умов; якщо У3 = F — працює пара «сума/лояльність»:
| К1 | К2 | К3 | К4 | |
|---|---|---|---|---|
| У1: сума ≥ 2000 | — | — | T | F |
| У2: лояльність | — | T | F | F |
| У3: промокод SALE | T | F | F | F |
| Знижка | 20% | 15% | 10% | 0% |
- Кожен «—» тут підтверджений — не специфікацією з першої спроби, а явною відповіддю аналітика. Це і є різниця між don't care як твердженням і don't care як лінню.
- К2 містить свій don't care у рядку суми: лояльність бʼє 10% за будь-якої суми («діє більша», 15% проти 10%). Вісім правил згорнулися до чотирьох без втрати логіки.
Кейс 2. Таблиця → параметризований тест
Згорнута таблиця майже дослівно перекладається в масив даних. Конкретні значення сум підбираємо граничними значеннями: межа предиката «сума ≥ 2000» дає точки 2000 і 1999.
import { test, expect } from '@playwright/test';
// колонки згорнутої таблиці = елементи масиву; тест один
const rules = [
{ name: 'К1: промокод перекриває решту знижок', promo: true, loyalty: true, total: 2500, discount: 20 },
{ name: 'К2: лояльність бʼє знижку за суму', promo: false, loyalty: true, total: 2500, discount: 15 },
{ name: 'К3: сума рівно 2000 — межа знижки 10%', promo: false, loyalty: false, total: 2000, discount: 10 },
{ name: 'К4: 1999 — без пільг знижки немає', promo: false, loyalty: false, total: 1999, discount: 0 },
];
for (const rule of rules) {
test(`знижка — ${rule.name}`, async ({ request }) => {
const res = await request.post('/api/cart/discount', {
data: { promoCode: rule.promo ? 'SALE' : null, loyalty: rule.loyalty, total: rule.total },
});
expect(res.status()).toBe(200);
expect((await res.json()).discountPercent).toBe(rule.discount);
});
}
Що дивитися і чому:
- Назва тесту описує правило, а не кроки. Впав «К2: лояльність бʼє знижку за суму» — зі звіту одразу видно, яка комбінація зламалася, без розкопування кроків.
- К3 і К4 — дві точки однієї межі. Off-by-one баги живуть саме на 1999/2000, тож для правил, де сума значуща, беремо граничні значення, а не «круглі» числа.
- Для don't care у К1 значення вибрані свідомо: loyalty: true заодно зачіпає гілку «промокод поверх лояльності» — ту саму, що була знаком питання в чернетці.
- Додалась умова у вимогах — додається колонка й рядок масиву. Сам тест не переписується; набір тестів лишається дзеркалом таблиці.
Кейс 3. «Неможлива» комбінація приходить через API
Специфікація доставки з глави каже: преміум-підписка доступна лише залогіненим, тож колонку «гість із преміумом» із таблиці викреслили. Але UI — не єдиний вхід у систему: прямий запит до API може принести викреслену комбінацію, і система має відповісти контрольовано, а не падати.
test('гість із преміум-прапорцем: контрольована відмова, не 500', async ({ request }) => {
// UI такого запиту не збере — шлемо руками, без токена авторизації
const res = await request.post('/api/shipping/quote', {
data: { premium: true, total: 200 },
});
// конкретний код звіряємо з контрактом API; головне — свідомий 4xx, не падіння
expect([400, 401, 403]).toContain(res.status());
});
Що дивитися і чому:
- Викреслити з таблиці — так, викреслити з голови — ні. Кожна «неможлива» колонка — кандидат на негативну перевірку, якщо комбінація може прийти ззовні: прямий виклик API, розсинхрон даних, гонка двох запитів.
- Оракул тут — не бізнес-результат, а гідна відмова. 500 із стектрейсом на «неможливому» вводі — це пропущена валідація на бекенді, окремий дефект незалежно від того, звідки прийшов тригер.
Коли техніка доречна
- Розумію, що таблиця рішень ловить баги в комбінаціях умов, які не ловляться перевірками кожної умови окремо.
- Впізнаю сигнал у вимогах: кілька речень «якщо… і… то…», що посилаються на ті самі поля; типові кандидати — знижки, тарифи, права доступу, валідація заявки.
- Знаю межі техніки: діапазон одного поля — класи еквівалентності плюс межі; залежність від історії — переходи станів; багато слабозвʼязаних параметрів — попарне тестування.
- Можу пояснити, чому таблиця — «фотографія» логіки в один момент часу, і коли вона збреше (та сама комбінація умов дає різний результат залежно від передісторії).
Структура і повна таблиця
- Знаю три частини таблиці: умови (рядки, T/F у limited-entry формі), дії (рядки, X), правила (колонки) — і як читати правило зверху вниз.
- Розумію формулу 2^n: три умови — 8 правил, пʼять — 32, десять — 1024; тому таблицю будують для добірки з 3–5 звʼязаних умов.
- Знаю, що умова-діапазон заходить у таблицю як готовий предикат («сума ≥ 1000») після розбиття на класи еквівалентності, а не як «сира» умова з кількома порогами.
- Розумію, що повна таблиця — чернетка: її цінність у систематичному переборі, який не губить комбінацій і виявляє прогалини вимог.
Згортання таблиці
- Можу пояснити don't care («—»): значення умови не впливає на результат — і чому це твердження, а не дозвіл не думати.
- Знаю правило: кожен don't care підтверджується специфікацією або перевіркою; є сумнів — лишаю обидві колонки.
- Розумію, що неможливі комбінації викреслюють із таблиці, але не з голови: якщо комбінація може прийти ззовні (API в обхід UI, розсинхрон даних) — це негативна перевірка.
- Можу пояснити, чому згортання не втрачає покриття логіки: кожне вихідне правило або неможливе, або накрите однією зі згорнутих колонок.
- Знаю, що дві колонки з однаковими умовами й різними діями — найчастіше суперечність у вимогах, і це знахідка, а не помилка заповнення.
Від правила до тест-кейсу
- Знаю мінімальне покриття: один тест-кейс на кожне правило згорнутої таблиці; покриття = перевірені колонки поділити на всі.
- Розумію розподіл ролей: правило задає логіку кейсу, конкретні дані дають класи еквівалентності та граничні значення (999 і 1000 для межі «≥ 1000»).
- Можу перекласти таблицю в параметризований автотест: колонки — масив даних, назва тесту описує правило, нова умова — новий рядок масиву без переписування тесту.
Cause-effect і рев'ю вимог
- Знаю, що таке причинно-наслідковий граф (cause-effect graph, Маєрс): причини й наслідки, звʼязки І/АБО/НЕ, обмеження між причинами.
- Розумію, що граф і таблиця — два подання однієї логіки, і коли граф вартий зусиль: заплутані й суперечливі вимоги, де конфлікт речень видно як конфлікт звʼязків.
- Можу пояснити «рев'ю вимог безкоштовно»: заповнення таблиці знаходить дірки й суперечності специфікації до написання коду — прояв принципу раннього тестування.
У вимогах кілька речень «якщо… і… то…», що посилаються на ті самі поля з різних кінців сторінки. Яку техніку тест-дизайну брати першою?
Питання
Таблиця рішень (decision table) — для якої логіки ця техніка?