Что такое эквивалентное разбиение?

Эквивалентное разбиение (Equivalence Partitioning, EP) — одна из самых фундаментальных техник тест-дизайна чёрного ящика. Основная идея проста, но мощна: вместо тестирования каждого возможного входного значения вы делите область входных данных на классы эквивалентности — группы значений, которые система должна обрабатывать одинаково.

Если система корректно обрабатывает одно значение из класса, она должна корректно обрабатывать все значения в этом классе. Это допущение позволяет сократить тысячи потенциальных тест-кейсов до управляемого количества.

Почему это важно

Рассмотрим поле, принимающее целые числа от 1 до 10 000. Тестирование каждого значения потребует 10 000 тест-кейсов — плюс невалидные значения. С эквивалентным разбиением достаточно всего 3 тест-кейсов:

КлассДиапазонПредставительОжидаемый результат
Невалидный (нижний)< 1-5Ошибка
Валидный1–10 0004 500Принять
Невалидный (верхний)> 10 00020 000Ошибка

Вы перешли от 10 000+ тестов к 3, при этом покрыв всю основную логику.

Процесс

flowchart TD A[Определить область входных данных] --> B[Разделить на классы эквивалентности] B --> C[Определить валидные классы] B --> D[Определить невалидные классы] C --> E[Выбрать одного представителя для каждого класса] D --> E E --> F[Разработать тест-кейсы]

Шаг 1: Определить область входных данных. Изучите спецификацию, чтобы понять, что принимает поле или параметр.

Шаг 2: Разделить на классы эквивалентности. Сгруппируйте значения, которые должны обрабатываться одинаково. Каждый класс должен быть взаимоисключающим — значение принадлежит ровно одному классу.

Шаг 3: Выбрать представителей. Выберите одно значение из каждого класса. Избегайте граничных значений — они покрываются отдельной техникой (Boundary Value Analysis).

Шаг 4: Написать тест-кейсы. Создайте один тест-кейс на каждое репрезентативное значение.

Типы классов эквивалентности

Валидные классы содержат значения, которые система должна принимать и обрабатывать нормально.

Невалидные классы содержат значения, которые система должна отклонять или обрабатывать как ошибки.

Частая ошибка — фокусироваться только на валидных классах. Невалидные классы часто выявляют больше дефектов, потому что обработка ошибок обычно недостаточно протестирована.

Применение EP к различным типам данных

Эквивалентное разбиение работает с любым типом входных данных:

Числовые диапазоны:

  • Поле возраста (18-65): классы — <18, 18-65, >65

Строковые данные:

  • Username (3-20 символов, буквенно-цифровые): классы включают валидную длину + валидные символы, слишком короткий, слишком длинный, спецсимволы, пустую строку

Перечисления:

  • Способ оплаты (кредитная карта, дебетовая карта, PayPal): каждый вариант — отдельный валидный класс; неподдерживаемый способ — невалидный класс

Boolean:

  • Checkbox (отмечен/не отмечен): два валидных класса
graph LR subgraph "Ввод возраста: 18-65" A["❌ < 18
напр., 10"] --- B["✅ 18-65
напр., 35"] B --- C["❌ > 65
напр., 80"] end

Реальный пример: Скидка в интернет-магазине

Магазин применяет скидки в зависимости от суммы корзины:

Сумма корзиныСкидка
$0 – $49.990%
$50 – $99.995%
$100 – $199.9910%
$200+15%

Классы эквивалентности:

#КлассПредставительОжидаемая скидка
1Отрицательные значения (невалидный)-$10Ошибка
2$0 – $49.99$250%
3$50 – $99.99$755%
4$100 – $199.99$15010%
5$200+$30015%

Пять тест-кейсов покрывают всю логику скидок.

Продвинутое эквивалентное разбиение

Разбиение с несколькими параметрами

Реальные приложения редко имеют один входной параметр. Когда параметров несколько, каждый имеет свой набор классов эквивалентности. Задача — эффективно их комбинировать.

Пример: Форма регистрации пользователя

ПараметрВалидные классыНевалидные классы
Возраст18-120<18, >120, нечисловой
Emailвалидный форматбез @, без домена, пустой
Пароль8-64 символа с заглавной, строчной буквой и цифройслишком короткий, слишком длинный, нет обязательных символов

Для тестирования валидных классов создайте один тест-кейс, использующий валидного представителя каждого параметра одновременно:

Тест-кейс 1: Возраст=30, Email=user@test.com, Пароль=Secure1pass
Ожидаемый результат: Регистрация успешна

Для тестирования невалидных классов меняйте один параметр за раз, оставляя остальные валидными:

Тест-кейс 2: Возраст=15, Email=user@test.com, Пароль=Secure1pass
Ожидаемый результат: Ошибка валидации возраста

Тест-кейс 3: Возраст=30, Email=невалидный-email, Пароль=Secure1pass
Ожидаемый результат: Ошибка валидации email

Этот подход называется Single Fault Assumption (допущение единичной ошибки) — тестирование одного невалидного параметра за раз для изоляции того, какая валидация срабатывает.

Разбиение на основе выходных данных

Иногда эффективнее строить разбиение на основе выходных данных, а не входных. Если функция возвращает разные типы результатов, работайте в обратном направлении:

def categorize_bmi(bmi):
    if bmi < 18.5:
        return "Недостаточный вес"
    elif bmi < 25:
        return "Норма"
    elif bmi < 30:
        return "Избыточный вес"
    else:
        return "Ожирение"

Разделы выходных данных: Недостаточный вес, Норма, Избыточный вес, Ожирение. Подберите один вход, который активирует каждый выход.

Типичные ошибки

  1. Пропуск «пустого» класса. Всегда рассматривайте пустую строку, null или ноль как отдельный класс.
  2. Игнорирование типов данных. Числовое поле может получить буквы — это отдельный невалидный класс.
  3. Пересекающиеся классы. Каждое значение должно принадлежать ровно одному классу. Если классы пересекаются, разбиение выполнено неверно.
  4. Слишком мало невалидных классов. Обычно невалидных классов больше, чем валидных.

Упражнение: Спроектируйте классы эквивалентности

Сценарий: Система бронирования авиабилетов принимает следующие входные данные:

  • Пассажиры: 1–9 (целое число)
  • Класс: Economy, Business, First
  • Тип поездки: В одну сторону, Туда и обратно

Задание: Определите все классы эквивалентности для каждого параметра и напишите минимальный набор тест-кейсов.

Подсказка

Для Пассажиров: подумайте, что происходит с 0, отрицательными числами, 10+, дробными числами и нечисловым вводом.

Для Класса и Типа поездки: каждый допустимый вариант — отдельный класс. А что с вариантом, которого не существует?

Решение

Пассажиры:

#КлассПредставительВалидный?
11–94Да
2< 10Нет
3> 915Нет
4Не целое число2.5Нет
5Нечисловой“abc”Нет

Класс обслуживания:

#КлассПредставительВалидный?
6EconomyEconomyДа
7BusinessBusinessДа
8FirstFirstДа
9Неподдерживаемый“Premium”Нет

Тип поездки:

#КлассПредставительВалидный?
10В одну сторонуВ одну сторонуДа
11Туда и обратноТуда и обратноДа
12Неподдерживаемый“Мульти-город”Нет

Минимальные тест-кейсы:

Валидные (все валидные представители вместе):

TC1: Пассажиры=4, Класс=Economy, Поездка=В одну сторону → Успех
TC2: Пассажиры=4, Класс=Business, Поездка=Туда и обратно → Успех
TC3: Пассажиры=4, Класс=First, Поездка=В одну сторону → Успех

Невалидные (один невалидный за раз):

TC4: Пассажиры=0, Класс=Economy, Поездка=В одну сторону → Ошибка
TC5: Пассажиры=15, Класс=Economy, Поездка=В одну сторону → Ошибка
TC6: Пассажиры=2.5, Класс=Economy, Поездка=В одну сторону → Ошибка
TC7: Пассажиры="abc", Класс=Economy, Поездка=В одну сторону → Ошибка
TC8: Пассажиры=4, Класс="Premium", Поездка=В одну сторону → Ошибка
TC9: Пассажиры=4, Класс=Economy, Поездка="Мульти-город" → Ошибка

Итого: 9 тест-кейсов, покрывающих 12 классов эквивалентности.

Советы профессионала

  • Комбинируйте EP с Boundary Value Analysis. EP сокращает пространство входных данных; BVA фокусируется на границах каждого класса. Вместе они составляют основу тестирования на основе спецификаций.
  • Документируйте разделы. Перед написанием тест-кейсов перечислите все классы эквивалентности в таблице. Это упрощает ревью и обеспечивает полноту.
  • Пересматривайте разделы при изменении спецификаций. Изменение валидного диапазона или нового типа входных данных означает новые классы эквивалентности.
  • Используйте EP и для параметров API. Каждый параметр API-эндпоинта имеет валидные и невалидные классы — применяйте ту же технику к телу запроса, query-параметрам и заголовкам.