Pairwise testing

Как сокращать взрыв комбинаций параметров через pairwise testing и где этот подход даёт реальную экономию без потери качества.

Обновлено:

Содержание

Когда у системы много параметров и значений, полный перебор комбинаций становится слишком дорогим. Pairwise testing помогает сократить их число, оставив покрытие всех пар значений между параметрами. На практике это часто даёт хороший баланс между стоимостью и шансом найти дефекты.

Почему pairwise работает

Многие дефекты проявляются из-за взаимодействия двух факторов, а не из-за редкой комбинации сразу пяти или шести параметров. Поэтому покрытие всех пар значений часто ловит значимую часть проблем при гораздо меньшем количестве тестов.

Где применять

  • →Формы с несколькими независимыми полями и значениями.
  • →Конфигурации устройств, браузеров, ролей, тарифов, стран, языков.
  • →API с множеством параметров и режимов вызова.
  • →Матрицы совместимости, где полный перебор слишком дорогой.

О чём важно помнить

  • →Pairwise не заменяет тесты на критичные бизнес-риски и известные опасные комбинации.
  • →Если есть зависимые параметры, их нельзя слепо смешивать как независимые.
  • →Некоторые комбинации логически невозможны и должны быть заранее исключены.
  • →Критичные сценарии нужно добавлять поверх generated pairwise-набора, а не вместо них.

Практическая best practice

Используй pairwise как инструмент оптимизации, а не как оправдание для минимального покрытия. Сначала выделяй high-risk cases вручную, потом добавляй pairwise для ширины покрытия, а затем усиливай набор негативными и пограничными сценариями.

🧩

Pairwise полезен тогда, когда проблема действительно в комбинациях параметров. Для сложной последовательной логики, состояний или расчётов он не является универсальным решением.

Пример: четыре теста покрывают все двенадцать пар

В учебной модели три фактора: браузер Chrome или Firefox, язык интерфейса ru или en, роль viewer или editor. Допустимы все восемь комбинаций. Версии браузеров, ОС, данные и feature flags в упражнении фиксированы; при реальном запуске запишите точные значения. Это модель выбора входных условий, а не готовое веб-приложение.

Полный перебор содержит 2 × 2 × 2 = 8 строк. Для pairwise нужны все пары значений разных факторов: четыре пары браузер–язык, четыре браузер–роль и четыре язык–роль. Следующие четыре строки покрывают эти двенадцать пар.

plain text
ID	Browser	Locale	Role
PW1	Chrome	ru	viewer
PW2	Chrome	en	editor
PW3	Firefox	ru	editor
PW4	Firefox	en	viewer

Проверяем покрытие, а не только число тестов

plain text
Фактор A	Фактор B	Покрывается тестом
Browser=Chrome	Locale=ru	PW1
Browser=Chrome	Locale=en	PW2
Browser=Firefox	Locale=ru	PW3
Browser=Firefox	Locale=en	PW4
Browser=Chrome	Role=viewer	PW1
Browser=Chrome	Role=editor	PW2
Browser=Firefox	Role=viewer	PW4
Browser=Firefox	Role=editor	PW3
Locale=ru	Role=viewer	PW1
Locale=ru	Role=editor	PW3
Locale=en	Role=viewer	PW4
Locale=en	Role=editor	PW2

В каждой строке указаны обязательная пара и тест, где она встречается. Все пары покрыты по одному разу. Четыре теста — минимум именно для этой независимой двоичной модели: четыре пары браузер–язык уже требуют хотя бы четырёх строк. Этот вывод нельзя переносить на произвольные pairwise-наборы.

Проверка матрицы на Python 3

Сохраните код как pairwise_coverage.py и запустите python3 pairwise_coverage.py. Нужна только стандартная библиотека; сетевых запросов нет. Ожидаемый вывод: Pairs: 12/12; triples: 4/8.

plain text
from itertools import product, combinations
levels = [("Chrome", "Firefox"), ("ru", "en"), ("viewer", "editor")]
rows = [
    ("Chrome", "ru", "viewer"),
    ("Chrome", "en", "editor"),
    ("Firefox", "ru", "editor"),
    ("Firefox", "en", "viewer"),
]
required = {(i, a, j, b) for i, j in combinations(range(3), 2)
            for a, b in product(levels[i], levels[j])}
covered = {(i, row[i], j, row[j]) for row in rows
           for i, j in combinations(range(3), 2)}
assert all(row in set(product(*levels)) for row in rows)
assert covered == required
assert ("Chrome", "en", "viewer") not in rows
print(f"Pairs: {len(covered)}/{len(required)}; triples: {len(set(rows))}/8")

Для каждой конфигурации нужен ожидаемый результат

Для вымышленного редактора документов заранее задайте правило: viewer читает документ, но попытка редактирования не меняет сохранённый текст; editor сохраняет допустимое изменение ровно один раз. В каждой строке матрицы проверьте язык, результат для роли и сохранённые данные. Покрытие пар само по себе этих результатов не доказывает: без проверок недостаточно просто открыть конфигурацию.

Матрица пропустит дефект, возникающий только при Chrome + en + viewer: такой тройки нет, хотя все её пары встречаются в других строках. Добавьте комбинацию, если это оправдывают риск или прошлый дефект. Последовательности, границы, права и производительность требуют отдельного тест-дизайна. Из «12/12 пар» не следует процент обнаруженных ошибок.

Если комбинация невозможна по правилам продукта, сначала получите допустимые полные комбинации, из них выведите достижимые пары, затем заново постройте и проверьте сокращённый набор. Простое удаление строки может убрать другие допустимые пары. Упражнение: удалите PW4; непокрытыми станут Firefox–en, Firefox–viewer и en–viewer. Восстановите покрытие допустимой строкой, а не уменьшайте знаменатель без объяснения.

Продолжить изучение

Выбор дополнительных тестов по рискам

Планирование кросс-браузерных проверок

NIST: combinatorial testing and interaction coverage