Попарне тестування й комбінаторика
Зміст
Форма оплати має пʼять параметрів по три-чотири значення кожен — і раптом чесне «перевірити всі комбінації» перетворюється на сотні тест-кейсів, які ніхто ніколи не виконає. Попарне тестування (pairwise testing) — техніка, яка стискає цей набір до пари десятків рядків, і робить це не «на око», а з чіткою математичною гарантією: кожна пара значень будь-яких двох параметрів зустрінеться хоча б в одному тесті. На співбесідах ця тема спливає у двох формах: пряме «що таке pairwise» і замасковане «як би ви тестували форму з N параметрами» — і друга форма підступніша, бо перевіряє, чи вмієте ви рахувати комбінації взагалі.
Це глава-поглиблення: при першому проході розділу її можна пропустити й повернутися після «Вибір і комбінування технік». Базовий трек — класи еквівалентності, граничні значення і таблиці рішень — самодостатній без неї. Але якщо у вашому продукті є конфігураційна матриця «браузери × ОС × ролі» або форма з купою незалежних опцій — ця техніка окупиться швидко.
Комбінаторний вибух
Кількість повних комбінацій — це добуток кількостей значень кожного параметра. Візьмімо чекаут інтернет-магазину:
| Параметр | Значення | Кількість |
|---|---|---|
| Спосіб оплати | картка, PayPal, Apple Pay | 3 |
| Валюта | USD, EUR, UAH | 3 |
| Доставка | курʼєр, самовивіз, поштомат | 3 |
| Платформа | web, iOS, Android | 3 |
Повний перебір: 3 × 3 × 3 × 3 = 81 тест. Додаємо промокод (є/немає) — уже 162. Додаємо стан користувача (гість/залогінений) — 324. Кожен новий параметр множить, а не додає — саме тому це називають комбінаторним вибухом (combinatorial explosion). Для конфігураційної матриці на кшталт «4 браузери × 3 ОС × 4 вʼюпорти × 2 локалі» це 96 повних прогонів сюїти — і жодна команда стільки не потягне на кожен реліз.
Це практична ілюстрація другого принципу тестування: вичерпне тестування неможливе (детальніше — розділ «Основи тестування»). Питання не «як перевірити все», а «як вибрати підмножину, що ловить максимум багів за мінімум тестів». Перший крок скорочення ви вже знаєте: значення кожного параметра — це не «всі можливі», а представники класів еквівалентності плюс межі. Другий крок — скоротити самі комбінації. Тут і починається комбінаторика.
Гіпотеза попарності
На чому ґрунтується право викинути більшість комбінацій? На емпіричному спостереженні: переважна більшість дефектів спричинена або одним параметром окремо, або взаємодією двох. Дослідники NIST (Kuhn зі співавторами) розбирали звіти про відмови реальних систем — медичного ПЗ, браузера, сервера, розподіленої бази даних — і виявили: значну частку відмов тригерить одне-єдине значення, разом із парними взаємодіями це закриває переважну більшість, а відмов, що вимагали збігу понад шести параметрів, у вивчених системах не зафіксували взагалі.
Звідси гіпотеза попарності: якщо набір тестів покриває кожну пару значень кожних двох параметрів, він зловить більшість дефектів взаємодії за малу частку вартості повного перебору. Формально pairwise — це окремий випадок t-wise покриття при t = 2: можна вимагати покриття всіх трійок (3-wise), четвірок і далі — кількість тестів зростає, але лишається незрівнянно меншою за повний перебір. Математичне коріння техніки — ортогональні масиви (orthogonal arrays), які статистики використовували в планах експериментів задовго до тестування ПЗ.
Важливо чесно розуміти, що гарантія дає і чого не дає:
- Дає: будь-яка комбінація значень двох параметрів точно зустрінеться щонайменше в одному тесті.
- Не дає: конкретна трійка значень може не зустрітися ніколи. Баг, який відтворюється лише за збігу «Apple Pay + UAH + поштомат», pairwise-набір має право пропустити.
Тобто це усвідомлений розмін ризику на вартість, а не безкоштовний обід.
Побудова pairwise вручну
Для двох-трьох параметрів набір реально скласти руками — і на співбесіді це іноді просять зробити. Візьмемо мінімальний приклад: браузер (Chrome, Firefox, Safari), ОС (Windows, macOS), роль (admin, user). Повний перебір: 3 × 2 × 2 = 12 тестів.
Нижня межа pairwise-набору — добуток двох найбільших кількостей значень: тут 3 × 2 = 6, бо всі шість пар «браузер × ОС» мусять десь зʼявитися, а в одному тесті живе лише одна така пара. Алгоритм ручної побудови: виписати декартів добуток двох найбільших параметрів як каркас, а колонки решти параметрів заповнювати так, щоб кожне нове значення закривало ще не покриті пари.
| # | Браузер | ОС | Роль |
|---|---|---|---|
| 1 | Chrome | Windows | admin |
| 2 | Chrome | macOS | user |
| 3 | Firefox | Windows | user |
| 4 | Firefox | macOS | admin |
| 5 | Safari | Windows | admin |
| 6 | Safari | macOS | user |
Перевірте самі: усі 6 пар «браузер × ОС» на місці (каркас), усі 6 пар «браузер × роль» — рядки 1–6, усі 4 пари «ОС × роль» — рядки 1, 2 (або 6), 3, 4. Шість тестів замість дванадцяти, і жодна пара не втрачена.
На чотирьох-пʼяти параметрах ручне заповнення перетворюється на судоку: додав значення в один рядок — зламав покриття в іншому. Тому на практиці набір генерують інструментом.
PICT: генерація набору
PICT (Pairwise Independent Combinatorial Tool) — консольний opensource-інструмент від Microsoft, один із найпоширеніших для цієї задачі. Модель — звичайний текстовий файл: параметр, двокрапка, значення через кому.
PaymentMethod: Card, PayPal, ApplePay
Currency: USD, EUR, UAH
Shipping: Courier, Pickup, Locker
Platform: Web, iOS, Android
Запуск — одна команда:
pict model.txt
На виході — таблиця тест-кейсів (tab-separated), яка покриває всі пари: для моделі вище це близько десяти рядків замість 81 повної комбінації. За замовчуванням PICT генерує саме пари; ключ /o піднімає порядок взаємодії — pict model.txt /o:3 покриє всі трійки, якщо аналіз ризиків каже, що пар замало.
Constraints: неможливі комбінації
У реальних системах параметри рідко повністю незалежні: Apple Pay не існує на Android, Safari не живе на Windows. Перша інтуїція — згенерувати набір і викреслити безглузді рядки руками — неправильна: разом із рядком ви викидаєте всі валідні пари, які він покривав, і в наборі зʼявляються діри, яких ніхто не бачить.
Правильний шлях — описати обмеження (constraints) у самій моделі, тоді генератор перекладе валідні пари в інші рядки:
IF [PaymentMethod] = "ApplePay" THEN [Platform] <> "Android";
IF [Platform] = "iOS" THEN [Shipping] <> "Locker";
Ще дві можливості PICT, які варто знати:
- Невалідні значення позначаються тильдою (
~ExpiredCard): PICT гарантує не більше одного невалідного значення на рядок — це та сама дисципліна «кожен невалідний клас окремим тестом» із глави про класи еквівалентності, тільки автоматизована. - Сідінг (seeding) — файл із обовʼязковими комбінаціями (ключ
/e): бізнес-критичні сценарії, які мусять бути в наборі, фіксуються явно, а генератор добудовує решту покриття навколо них.
Коли pairwise недостатньо
Pairwise — інструмент для одного конкретного класу задач: багато незалежних параметрів, кожна валідна комбінація має сенс, результат не залежить від хитрої логіки між умовами. Поза цим класом техніка або мовчки пропускає баги, або просто не застосовна:
- Логіка між умовами. Якщо «знижка 10% дається тільки залогіненому з промокодом при сумі понад 1000» — це не незалежні параметри, а бізнес-правила. Тут потрібна таблиця рішень: вона перелічує правила явно й дає очікуваний результат для кожного.
- Послідовність має значення. Pairwise комбінує значення, але нічого не знає про порядок дій. Сценарії «скасувати після оплати, але до відправлення» — територія переходів станів.
- Відомі ризиковані трійки. Якщо аналітика багів чи досвід підказує, що конкретні три параметри взаємодіють (оплата × валюта × платіжний шлюз), — підніміть порядок до 3-wise для цієї підмножини або зафіксуйте комбінації сідінгом. Ризик-орієнтований підхід до вибору глибини — канонічно в розділі «Основи тестування».
- Проблема оракула. Генератор видає входи, але не каже, який результат очікувати в кожному рядку. Якщо очікуваний результат для довільної комбінації визначити важко — виграш від згенерованих 200 рядків ілюзорний: ви не зможете їх перевірити.
Комбінаторика в конфігураційному тестуванні
Найчастіше pairwise у вебі застосовують не до полів форми, а до конфігураційної матриці: браузери × ОС × вʼюпорти × локалі. Логіка та сама, але з двома особливостями.
Перша: значення параметрів беруться не зі специфікації, а з аналітики користувачів. Немає сенсу тримати в матриці комбінацію, якою користується 0.1% аудиторії, і пропустити ту, де сидить 40%. Спершу ріжеться список значень (реальні браузери й пристрої вашої аудиторії), потім pairwise ріже комбінації.
Друга: конфігурації нерівноцінні за вартістю. Прогнати сюїту в headless Chromium — хвилини; на реальному Safari під macOS у фермі — набагато дорожче. Тому типова стратегія — асиметрична: повна сюїта на основній конфігурації, pairwise-редукована матриця на решті, і смоук — на екзотиці.
В автоматизації конфігураційна матриця живе прямо в конфігурації ранера. У Playwright це projects — кожен рядок вашого pairwise-набору стає окремим проєктом:
// playwright.config.ts — pairwise-редукована матриця замість повної
export default defineConfig({
projects: [
{ name: 'chromium-desktop-uk', use: { ...devices['Desktop Chrome'], locale: 'uk-UA' } },
{ name: 'webkit-desktop-en', use: { ...devices['Desktop Safari'], locale: 'en-US' } },
{ name: 'firefox-desktop-en', use: { ...devices['Desktop Firefox'], locale: 'en-US' } },
{ name: 'chromium-mobile-en', use: { ...devices['Pixel 7'], locale: 'en-US' } },
],
});
Повна матриця «3 рушії × 2 форм-фактори × 2 локалі» — це 12 проєктів; строгий pairwise дав би 6 (нижня межа — 3 × 2, як у ручному прикладі вище). Чотири рядки вище — наступний крок редукції, уже ризик-орієнтований: кожен рушій проганяється хоча б раз, а «дорогі» пари з локаллю uk-UA і мобільним вʼюпортом лишаються тільки на основному рушії аудиторії. Це і є типова еволюція матриці: повний перебір → pairwise → підрізання за аналітикою. Той самий принцип працює для матриць у CI (стратегія прогонів — розділ «Git і CI/CD») і для кросбраузерного тестування верстки (окрема глава в розділі «Веб і мережі»).
Типові помилки
- Виглядає як «pairwise покрив усі комбінації», а насправді він гарантує лише пари: трійка «Apple Pay + UAH + поштомат» може не зустрітися в жодному рядку, і баг на її перетині набір пропустить. Скорочення — це прийнятий ризик, і його треба вміти назвати вголос.
- Виглядає як «згенерував набір, викреслив неможливі рядки — готово», а насправді разом із рядком випали валідні пари, які він покривав. Неможливі комбінації описуються constraints у моделі — тоді генератор перекриє пари іншими рядками.
- Виглядає як «параметр = поле, значення = все, що є в дропдауні», а насправді значення мають бути представниками класів еквівалентності й межами. Пхати в модель 25 країн замість 3–4 класів — отримати вибух ще до генерації.
- Виглядає як «інструмент згенерував 15 тестів — тест-дизайн готовий», а насправді генератор видав лише входи. Очікуваний результат кожного рядка все одно визначає людина; без оракула це не тести, а перелік натискань.
- Виглядає як «критичні сценарії якось потраплять у набір», а насправді генератор нічого не знає про бізнес-ризик. Комбінацію, на якій компанія заробляє гроші, фіксують сідінгом явно — а не сподіваються на випадковість.
Підсумок
- Повний перебір росте як добуток кількостей значень параметрів — кожен новий параметр множить, а не додає. Тому вичерпне комбінування неможливе майже одразу.
- Pairwise гарантує рівно одне: кожна пара значень будь-яких двох параметрів зустрінеться хоча б в одному тесті. Трійки й глибші взаємодії — поза гарантією; за потреби порядок піднімають до t-wise.
- Значення для комбінаторики — представники класів еквівалентності й межі, а не сирий перелік із UI. Спершу ріжуться значення, потім — комбінації.
- Неможливі комбінації описуються constraints у моделі, критичні — фіксуються сідінгом. Ручне викреслювання рядків руйнує покриття непомітно.
- Pairwise — для незалежних параметрів. Логіка між умовами — таблиці рішень; послідовності — переходи станів; вибір за контекстом — глава про комбінування технік.
Що питають на співбесіді
- «Форма має 5 параметрів по 4 значення. Скільки тестів для повного перебору і як скоротити?» — Чекають миттєвого 4^5 = 1024 і слова «pairwise» з поясненням гарантії. Інтервʼюер дивиться, чи вмієте ви взагалі порахувати добуток і чи розумієте, що саме втрачається при скороченні.
- «Що гарантує попарне тестування і чого не гарантує?» — Сильна відповідь: гарантує покриття всіх пар, не гарантує трійок; згадка гіпотези попарності (більшість багів — взаємодія одного-двох параметрів, дані NIST) і що це усвідомлений розмін ризику на вартість.
- «Якими інструментами будували pairwise-набір?» — Достатньо PICT: модель, constraints, ключ порядку взаємодії. Червоний прапорець для інтервʼюера — кандидат чув слово, але не знає, що робити з неможливими комбінаціями.
- «Як ви обрали б браузерну матрицю для регресії?» — Дивляться на порядок міркування: аналітика аудиторії → значення параметрів → pairwise-редукція → асиметрія (повна сюїта на основній конфігурації, смоук на решті). Відповідь «тестуємо на всьому» — програшна, бо ігнорує вартість.
- «Коли pairwise застосовувати не варто?» — Перевірка зрілості: залежні параметри й бізнес-правила (таблиця рішень), важливий порядок дій (переходи станів), нема оракула для довільної комбінації. Кандидат, який знає межі техніки, цінніший за того, хто застосовує її всюди.
Формат розгорнутої відповіді на задачі типу «протестуйте форму» — у главі «Класичні задачі співбесід».
Джерела
- Microsoft PICT — інструмент і вихідний код; повна документація моделей: constraints, сідінг, невалідні значення, порядок взаємодії.
- NIST: Automated Combinatorial Testing for Software (ACTS) — емпіричні дослідження Куна зі співавторами, що обґрунтовують гіпотезу попарності, і безкоштовні матеріали з комбінаторного тестування.
- Силабус ISTQB CTFL 4.0 попарного тестування не містить — з чорноскринькових технік там лише класи еквівалентності, граничні значення, таблиці рішень і переходи станів. Комбінаторні техніки (зокрема pairwise) описані в силабусі ISTQB Advanced Level Test Analyst — розділ про техніки тест-дизайну.
Що таке комбінаторний вибух і чому не можна просто перевірити всі комбінації параметрів?
Кількість повних комбінацій — це добуток кількостей значень кожного параметра, і росте він множенням, а не додаванням. Чекаут із чотирма параметрами по три значення — це вже 3 × 3 × 3 × 3 = 81 тест; додали промокод (є/немає) — 162, додали стан користувача — 324. Для конфігураційної матриці «4 браузери × 3 ОС × 4 вʼюпорти × 2 локалі» повний перебір — 96 прогонів сюїти на кожен реліз, чого жодна команда не потягне. Це практична ілюстрація принципу «вичерпне тестування неможливе»: правильне питання не «як перевірити все», а «як вибрати підмножину, що ловить максимум багів за мінімум тестів».
Форма має 5 параметрів по 4 значення. Скільки тестів для повного перебору і як скоротити набір?
Повний перебір — 4^5 = 1024 тести, і саме миттєвий добуток тут чекають почути найперше. Скорочення двокрокове. Крок один: значення кожного параметра — це не «все, що є в дропдауні», а представники класів еквівалентності плюс межі, тож самих значень стає менше ще до комбінування. Крок два: замість повного перебору — попарне тестування (pairwise), яке стискає набір до пари десятків рядків із гарантією, що кожна пара значень будь-яких двох параметрів зустрінеться хоча б в одному тесті. Сильна відповідь обовʼязково називає ціну: трійки й глибші взаємодії лишаються поза гарантією, і це прийнятий ризик, а не безкоштовний обід.
Що таке попарне тестування (pairwise)?
Це техніка скорочення комбінацій із чіткою математичною гарантією: кожна пара значень будь-яких двох параметрів зустрінеться щонайменше в одному тесті. Замість сотень повних комбінацій виходить пара десятків рядків — для моделі з 81 комбінації PICT видає близько десяти. Формально pairwise — окремий випадок t-wise покриття при t = 2: можна вимагати покриття всіх трійок (3-wise) чи четвірок, кількість тестів зросте, але лишиться незрівнянно меншою за повний перебір. Математичне коріння — ортогональні масиви (orthogonal arrays), які статистики застосовували в планах експериментів задовго до тестування ПЗ.
Що гарантує pairwise-набір і чого не гарантує?
Гарантує рівно одне: будь-яка комбінація значень двох параметрів точно зустрінеться хоча б в одному тесті. Не гарантує нічого про трійки: конкретний збіг трьох значень може не зустрітися ніколи, тож баг, який відтворюється лише за «Apple Pay + UAH + поштомат», набір має право пропустити. Тобто це усвідомлений розмін ризику на вартість, і кандидата часто перевіряють саме на вмінні назвати цей ризик уголос. Якщо аналіз ризиків каже, що пар замало, порядок піднімають до 3-wise для ризикованої підмножини або фіксують критичні комбінації явно.
На чому ґрунтується право викидати більшість комбінацій? Що таке гіпотеза попарності?
На емпіричному спостереженні, а не на математичному доказі. Дослідники NIST (Kuhn зі співавторами) розбирали звіти про відмови реальних систем — медичного ПЗ, браузера, сервера, розподілених баз даних — і виявили: значну частку відмов тригерить одне-єдине значення, а разом із парними взаємодіями це закриває переважну більшість, тоді як відмов, що вимагали збігу понад шести параметрів, у вивчених системах не зафіксували взагалі. Звідси гіпотеза попарності: набір, який покриває кожну пару значень кожних двох параметрів, зловить більшість дефектів взаємодії за малу частку вартості повного перебору. Важливо памʼятати статус цього твердження: це статистика по вивчених системах, тому рідкісний баг на трійці все одно можливий — і саме тому скорочення називають прийнятим ризиком.
Як побудувати pairwise-набір вручну і скільки тестів у ньому буде щонайменше?
Нижня межа — добуток двох найбільших кількостей значень: усі пари двох «найширших» параметрів мусять десь зʼявитися, а в одному тесті живе лише одна така пара. Для «браузер (3) × ОС (2) × роль (2)» це 3 × 2 = 6 тестів замість 12 повного перебору. Алгоритм: виписати декартів добуток двох найбільших параметрів як каркас, а колонки решти параметрів заповнювати так, щоб кожне нове значення закривало ще не покриті пари. Наприкінці — перевірити себе: пройтися по всіх парах параметрів і переконатися, що жодна пара значень не втрачена. На чотирьох-пʼяти параметрах ручне заповнення перетворюється на судоку — додав значення в один рядок, зламав покриття в іншому, — тому на практиці набір генерують інструментом.
Що таке t-wise покриття і коли є сенс піднімати порядок понад пари?
t-wise — узагальнення pairwise: вимога покрити всі комбінації значень кожних t параметрів; pairwise — це t = 2, 3-wise покриває всі трійки і так далі. З ростом порядку кількість тестів зростає, але все одно лишається значно меншою за повний перебір. Піднімати порядок варто не «про всяк випадок», а коли аналітика багів чи досвід підказує, що конкретні три параметри реально взаємодіють — наприклад, оплата × валюта × платіжний шлюз. Тоді або піднімають порядок для цієї підмножини (у PICT — ключ /o:3), або фіксують відомі небезпечні комбінації сідінгом. Це ризик-орієнтований вибір глибини покриття, а не механічне «більше — краще».
Якими інструментами будують pairwise-набори? Розкажіть про PICT.
Стандартна відповідь — PICT (Pairwise Independent Combinatorial Tool), консольний opensource-інструмент від Microsoft, один із найпоширеніших. Модель — звичайний текстовий файл: параметр, двокрапка, значення через кому; запуск — одна команда pict model.txt. На виході — tab-separated таблиця тест-кейсів, що покриває всі пари; за замовчуванням генеруються саме пари, ключ /o піднімає порядок взаємодії. Знати варто ще три можливості: constraints для неможливих комбінацій, тильда для невалідних значень і сідінг для обовʼязкових комбінацій. Червоний прапорець для інтервʼюера — кандидат чув слово pairwise, але не знає, що робити з неможливими комбінаціями.
У згенерованому наборі є неможливі комбінації — наприклад, Apple Pay на Android. Що з ними робити?
Перша інтуїція — викреслити безглузді рядки руками — неправильна: разом із рядком викидаються всі валідні пари, які він покривав, і в наборі зʼявляються діри, яких ніхто не бачить. Правильний шлях — описати обмеження (constraints) у самій моделі, наприклад у PICT: IF [PaymentMethod] = "ApplePay" THEN [Platform] <> "Android";. Тоді генератор знає про заборону заздалегідь і перекладає валідні пари з неможливих рядків в інші — покриття лишається повним. Це типове питання на розуміння механіки, а не синтаксису: суть у тому, що покриття пар руйнується непомітно, і саме тому обмеження мусять жити в моделі, а не в голові тестувальника з олівцем.
Навіщо в PICT сідінг і позначка невалідних значень тильдою?
Сідінг (seeding) — файл із обовʼязковими комбінаціями (ключ /e): бізнес-критичні сценарії, які мусять бути в наборі, фіксуються явно, а генератор добудовує решту покриття навколо них. Без цього критична комбінація потрапляє в набір лише випадково — генератор нічого не знає про бізнес-ризик. Тильда (~ExpiredCard) позначає невалідне значення, і PICT гарантує не більше одного невалідного значення на рядок. Це автоматизована версія дисципліни «кожен невалідний клас окремим тестом» із класів еквівалентності: якщо в одному тесті два невалідні значення, спрацює перше, а друге лишиться неперевіреним у масці зеленого результату.
Звідки брати значення параметрів для комбінаторної моделі?
Не з UI дослівно: «параметр = поле, значення = все, що є в дропдауні» — типова помилка, яка дає вибух ще до генерації. Значення мають бути представниками класів еквівалентності плюс межами: не 25 країн, а 3–4 класи, які реально поводяться по-різному. Порядок скорочення завжди такий: спершу ріжуться значення, потім — комбінації. Для конфігураційної матриці джерело значень — ще й аналітика користувачів: немає сенсу тримати комбінацію, якою користується 0.1% аудиторії, і пропустити ту, де сидить 40%.
Як би ви обрали браузерну матрицю для регресії?
Тут дивляться на порядок міркування, а не на конкретні браузери. Крок один: аналітика аудиторії — реальні браузери, пристрої й локалі ваших користувачів визначають список значень. Крок два: pairwise-редукція комбінацій — повна матриця «3 рушії × 2 форм-фактори × 2 локалі» дає 12 конфігурацій, строгий pairwise — 6. Крок три: асиметрія за вартістю, бо конфігурації нерівноцінні — headless Chromium коштує хвилини, реальний Safari у фермі набагато дорожче; тому повна сюїта ганяється на основній конфігурації, pairwise-редукована матриця на решті, смоук — на екзотиці. Відповідь «тестуємо на всьому» — програшна, бо ігнорує вартість; в автоматизації кожен рядок такої матриці стає окремим проєктом у projects Playwright.
Коли pairwise застосовувати не варто?
Pairwise працює для одного класу задач: багато незалежних параметрів, кожна валідна комбінація має сенс, результат не залежить від логіки між умовами. Поза цим класом він або мовчки пропускає баги, або не застосовний. Якщо результат визначають бізнес-правила між залежними умовами («знижка тільки залогіненому з промокодом при сумі понад 1000») — це територія таблиці рішень, яка перелічує правила явно й дає очікуваний результат для кожного. Якщо важлива послідовність дій («скасувати після оплати, але до відправлення») — pairwise нічого не знає про порядок, потрібні переходи станів. Якщо відомі ризиковані трійки — піднімають порядок до 3-wise чи фіксують сідінгом. І нарешті, якщо для довільної комбінації важко визначити очікуваний результат, виграш від згенерованих рядків ілюзорний — їх не буде чим перевірити.
Інструмент згенерував 15 тестів — чи означає це, що тест-дизайн готовий?
Ні, і це перевірка на розуміння проблеми оракула. Генератор видає лише входи — комбінації значень параметрів; він не каже, який результат очікувати в кожному рядку. Очікуваний результат кожного тесту все одно визначає людина, звіряючись зі специфікацією чи бізнес-правилами: без оракула це не тести, а перелік натискань. Тому чесна оцінка вартості pairwise-набору включає не тільки генерацію, а й роботу з визначення очікуваних результатів — і якщо вона непідйомна для 200 рядків, можливо, сама задача не для комбінаторики, а для таблиці рішень із явними правилами.
Чи входить попарне тестування в силабус ISTQB CTFL?
Ні — і це корисно знати, щоб не шукати його там перед іспитом. У CTFL 4.0 із чорноскринькових технік лише класи еквівалентності, граничні значення, таблиці рішень і переходи станів. Комбінаторні техніки, включно з pairwise, описані на рівні ISTQB Advanced Level Test Analyst у розділі про техніки тест-дизайну. На співбесіді ж pairwise питають незалежно від силабуса — найчастіше в замаскованій формі «як би ви тестували форму з N параметрами», яка заразом перевіряє, чи вмієте ви взагалі рахувати комбінації.
Три кейси, де комбінаторика перестає бути теорією: ручна побудова pairwise-набору на дошці — саме так, як просять на співбесіді; PICT-модель чекаута з constraints, невалідними значеннями й сідінгом; і pairwise-редукція браузерної матриці в projects Playwright. Скрізь — що дивитися і чому.
Кейс 1. Побудувати pairwise-набір руками на співбесіді
Умова: конфігураційна матриця «браузер (Chrome, Firefox, Safari) × ОС (Windows, macOS) × роль (admin, user)». Повний перебір — 3 × 2 × 2 = 12 тестів. Просять скоротити без втрати пар.
Крок 1 — нижня межа. Два найбільші параметри — браузер (3) і ОС (2), отже менше ніж 3 × 2 = 6 тестів не вийде: всі шість пар «браузер × ОС» мусять десь зʼявитися, а в одному тесті живе лише одна така пара.
Крок 2 — каркас. Виписуємо декартів добуток двох найбільших параметрів — рівно 6 рядків, пари «браузер × ОС» покриті за побудовою.
Крок 3 — заповнення. Колонку ролі заповнюємо так, щоб закрити пари «браузер × роль» і «ОС × роль»: чергуємо значення й стежимо, щоб кожен браузер зустрівся з обома ролями і кожна ОС — з обома ролями.
| # | Браузер | ОС | Роль |
|---|---|---|---|
| 1 | Chrome | Windows | admin |
| 2 | Chrome | macOS | user |
| 3 | Firefox | Windows | user |
| 4 | Firefox | macOS | admin |
| 5 | Safari | Windows | admin |
| 6 | Safari | macOS | user |
Що дивитися і чому:
- Перевірка — по парах параметрів, а не «на око». Пари «браузер × ОС» — каркас, усі 6. Пари «браузер × роль» — кожен браузер має рядок з admin і рядок з user. Пари «ОС × роль» — Windows зустрічається з admin (рядки 1, 5) і user (рядок 3), macOS — з user (2, 6) і admin (4). Жодна пара не втрачена — 6 тестів замість 12.
- Скажіть уголос, що втрачено. Трійки: наприклад, комбінації «Safari + Windows + user» у наборі немає, і баг рівно на цьому збігу набір пропустить. Інтервʼюер чекає саме цієї чесності — скорочення є прийнятим ризиком.
- Чому це не масштабується руками. На чотирьох-пʼяти параметрах заповнення перетворюється на судоку: додане значення в одному рядку ламає покриття в іншому. Три параметри — межа розумного для дошки; далі — генератор.
Кейс 2. PICT: модель чекаута з constraints і сідінгом
Чекаут: спосіб оплати, валюта, доставка, платформа — повний перебір 3 × 3 × 3 × 3 = 81 комбінація. Модель PICT — звичайний текстовий файл:
PaymentMethod: Card, PayPal, ApplePay, ~ExpiredCard
Currency: USD, EUR, UAH
Shipping: Courier, Pickup, Locker
Platform: Web, iOS, Android
IF [PaymentMethod] = "ApplePay" THEN [Platform] <> "Android";
IF [Platform] = "iOS" THEN [Shipping] <> "Locker";
Запуск і варіації:
pict model.txt # pairwise: близько десятка рядків замість 81
pict model.txt /o:3 # усі трійки, якщо ризики кажуть, що пар замало
pict model.txt /e:seed.txt # сідінг: обовʼязкові комбінації з файлу
Файл сідінгу — бізнес-критичний сценарій, який мусить бути в наборі незалежно від примх генератора:
PaymentMethod Currency Shipping Platform
Card UAH Courier Web
Що дивитися і чому:
- Constraints замість олівця. Перша інтуїція — згенерувати без обмежень і викреслити рядки з «ApplePay + Android» руками — руйнує покриття: разом із рядком зникають усі валідні пари, які він покривав, і діри ніхто не побачить. Обмеження в моделі змушують генератор перекласти ці пари в інші рядки.
~ExpiredCard— не більше одного невалідного значення на рядок. Це автоматизована дисципліна «кожен невалідний клас окремим тестом» із класів еквівалентності: два невалідні значення в одному тесті маскують одне одного.- Сідінг — для грошей, не для краси. Генератор нічого не знає про бізнес-ризик: комбінацію, на якій компанія заробляє, фіксують явно, а не сподіваються, що вона випадково потрапить у набір.
- Вихід PICT — ще не тести. Це лише входи; колонку «очікуваний результат» додає людина, звіряючись зі специфікацією. Якщо для довільного рядка результат визначити неможливо — проблема оракула, і 200 згенерованих рядків нічого не варті.
Кейс 3. Playwright projects: pairwise-редукція браузерної матриці
Повна матриця «3 рушії × 2 форм-фактори × 2 локалі» — 12 проєктів на кожен прогін. Строгий pairwise дав би 6 (нижня межа — 3 × 2). Наступний крок редукції — ризик-орієнтований, за аналітикою аудиторії:
// playwright.config.ts — pairwise-редукована матриця замість повної
export default defineConfig({
projects: [
{ name: 'chromium-desktop-uk', use: { ...devices['Desktop Chrome'], locale: 'uk-UA' } },
{ name: 'webkit-desktop-en', use: { ...devices['Desktop Safari'], locale: 'en-US' } },
{ name: 'firefox-desktop-en', use: { ...devices['Desktop Firefox'], locale: 'en-US' } },
{ name: 'chromium-mobile-en', use: { ...devices['Pixel 7'], locale: 'en-US' } },
],
});
Що дивитися і чому:
- Значення — з аналітики, не зі специфікації. Спершу ріжеться список значень (реальні браузери й пристрої вашої аудиторії), потім pairwise ріже комбінації. Тримати конфігурацію для 0.1% користувачів і пропустити ту, де сидить 40%, — програш іще до генерації.
- Кожен рушій — хоча б раз. У чотирьох рядках вище всі три рушії присутні, а «дорогі» пари (локаль
uk-UA, мобільний вʼюпорт) лишаються тільки на основному рушії аудиторії — конфігурації нерівноцінні за вартістю, headless Chromium дешевший за Safari у фермі. - Асиметрія як стратегія. Повна сюїта — на основній конфігурації, редукована матриця — на решті, смоук — на екзотиці. Типова еволюція матриці: повний перебір, потім pairwise, потім підрізання за аналітикою.
- Чесно назвіть, що втрачено. Скорочення з 12 до 4 — прийнятий ризик: частина пар «рушій × локаль × форм-фактор» не прогониться ніколи. Якщо баг-аналітика покаже проблемну трійку — саме її повертають у матрицю явно, як сідінг у PICT.
Комбінаторний вибух
- Можу порахувати кількість повних комбінацій: добуток кількостей значень кожного параметра — і пояснити, чому новий параметр множить, а не додає.
- Розумію, що це практична ілюстрація принципу «вичерпне тестування неможливе»: питання не «як перевірити все», а «яка підмножина ловить максимум багів за мінімум тестів».
- Знаю двокроковий порядок скорочення: спершу ріжуться значення (представники класів еквівалентності плюс межі), потім — комбінації.
Гарантія pairwise
- Можу сформулювати гарантію дослівно: кожна пара значень будь-яких двох параметрів зустрінеться хоча б в одному тесті.
- Знаю, чого гарантія не дає: конкретна трійка може не зустрітися ніколи — і вмію назвати цей прийнятий ризик уголос.
- Можу пояснити гіпотезу попарності й послатися на дані NIST (Kuhn): більшість відмов тригерить один параметр або взаємодія пари, відмов на збігу понад шести параметрів не зафіксовано.
- Розумію, що pairwise — окремий випадок t-wise при
t = 2, знаю, коли ризик-орієнтовано піднімати порядок до 3-wise, і памʼятаю коріння техніки — ортогональні масиви (orthogonal arrays) з планування експериментів.
Побудова набору
- Можу порахувати нижню межу pairwise-набору: добуток двох найбільших кількостей значень.
- Можу вручну скласти набір для двох-трьох параметрів: каркас із декартового добутку двох найбільших, решта колонок заповнюється під ще не покриті пари.
- Знаю PICT: формат моделі («параметр: значення через кому»), запуск
pict model.txt, ключ/oдля порядку взаємодії.
Constraints і сідінг
- Можу пояснити, чому викреслювати неможливі рядки руками не можна: разом із рядком випадають валідні пари, і в покритті зʼявляються невидимі діри.
- Вмію описати неможливі комбінації через constraints у моделі (
IF ... THEN), щоб генератор переклав валідні пари в інші рядки. - Знаю, що невалідні значення позначаються тильдою і PICT дає не більше одного невалідного значення на рядок — та сама дисципліна «кожен невалідний клас окремим тестом».
- Можу пояснити сідінг (seeding): бізнес-критичні комбінації фіксуються явно у файлі (ключ
/e), генератор добудовує покриття навколо них.
Межі техніки
- Знаю клас задач pairwise: багато незалежних параметрів, кожна валідна комбінація має сенс, результат не залежить від логіки між умовами.
- Можу назвати, коли pairwise не підходить: бізнес-правила між залежними умовами — таблиця рішень; критична послідовність дій — переходи станів.
- Розумію проблему оракула: генератор видає лише входи, очікуваний результат кожного рядка визначає людина — без оракула це перелік натискань, а не тести.
Конфігураційне тестування
- Знаю, що значення конфігураційної матриці беруться з аналітики користувачів, а не зі специфікації: спершу ріжеться список значень, потім pairwise ріже комбінації.
- Можу пояснити асиметричну стратегію за вартістю: повна сюїта на основній конфігурації, pairwise-редукована матриця на решті, смоук — на екзотиці.
- Розумію, як pairwise-набір лягає в Playwright
projects: кожен рядок матриці — окремий проєкт, а еволюція матриці — повний перебір, потім pairwise, потім підрізання за аналітикою.
Форма має 4 параметри по 3 значення кожен. Скільки тестів потрібно для повного перебору комбінацій?
Питання
Комбінаторний вибух (combinatorial explosion) — що це і як рахується?