Что такое эквивалентное разбиение?
Эквивалентное разбиение (Equivalence Partitioning, EP) — одна из самых фундаментальных техник тест-дизайна чёрного ящика. Основная идея проста, но мощна: вместо тестирования каждого возможного входного значения вы делите область входных данных на классы эквивалентности — группы значений, которые система должна обрабатывать одинаково.
Если система корректно обрабатывает одно значение из класса, она должна корректно обрабатывать все значения в этом классе. Это допущение позволяет сократить тысячи потенциальных тест-кейсов до управляемого количества.
Почему это важно
Рассмотрим поле, принимающее целые числа от 1 до 10 000. Тестирование каждого значения потребует 10 000 тест-кейсов — плюс невалидные значения. С эквивалентным разбиением достаточно всего 3 тест-кейсов:
| Класс | Диапазон | Представитель | Ожидаемый результат |
|---|---|---|---|
| Невалидный (нижний) | < 1 | -5 | Ошибка |
| Валидный | 1–10 000 | 4 500 | Принять |
| Невалидный (верхний) | > 10 000 | 20 000 | Ошибка |
Вы перешли от 10 000+ тестов к 3, при этом покрыв всю основную логику.
Процесс
Шаг 1: Определить область входных данных. Изучите спецификацию, чтобы понять, что принимает поле или параметр.
Шаг 2: Разделить на классы эквивалентности. Сгруппируйте значения, которые должны обрабатываться одинаково. Каждый класс должен быть взаимоисключающим — значение принадлежит ровно одному классу.
Шаг 3: Выбрать представителей. Выберите одно значение из каждого класса. Избегайте граничных значений — они покрываются отдельной техникой (Boundary Value Analysis).
Шаг 4: Написать тест-кейсы. Создайте один тест-кейс на каждое репрезентативное значение.
Типы классов эквивалентности
Валидные классы содержат значения, которые система должна принимать и обрабатывать нормально.
Невалидные классы содержат значения, которые система должна отклонять или обрабатывать как ошибки.
Частая ошибка — фокусироваться только на валидных классах. Невалидные классы часто выявляют больше дефектов, потому что обработка ошибок обычно недостаточно протестирована.
Применение EP к различным типам данных
Эквивалентное разбиение работает с любым типом входных данных:
Числовые диапазоны:
- Поле возраста (18-65): классы —
<18,18-65,>65
Строковые данные:
- Username (3-20 символов, буквенно-цифровые): классы включают валидную длину + валидные символы, слишком короткий, слишком длинный, спецсимволы, пустую строку
Перечисления:
- Способ оплаты (кредитная карта, дебетовая карта, PayPal): каждый вариант — отдельный валидный класс; неподдерживаемый способ — невалидный класс
Boolean:
- Checkbox (отмечен/не отмечен): два валидных класса
Реальный пример: Скидка в интернет-магазине
Магазин применяет скидки в зависимости от суммы корзины:
| Сумма корзины | Скидка |
|---|---|
| $0 – $49.99 | 0% |
| $50 – $99.99 | 5% |
| $100 – $199.99 | 10% |
| $200+ | 15% |
Классы эквивалентности:
| # | Класс | Представитель | Ожидаемая скидка |
|---|---|---|---|
| 1 | Отрицательные значения (невалидный) | -$10 | Ошибка |
| 2 | $0 – $49.99 | $25 | 0% |
| 3 | $50 – $99.99 | $75 | 5% |
| 4 | $100 – $199.99 | $150 | 10% |
| 5 | $200+ | $300 | 15% |
Пять тест-кейсов покрывают всю логику скидок.
Продвинутое эквивалентное разбиение
Разбиение с несколькими параметрами
Реальные приложения редко имеют один входной параметр. Когда параметров несколько, каждый имеет свой набор классов эквивалентности. Задача — эффективно их комбинировать.
Пример: Форма регистрации пользователя
| Параметр | Валидные классы | Невалидные классы |
|---|---|---|
| Возраст | 18-120 | <18, >120, нечисловой |
| валидный формат | без @, без домена, пустой | |
| Пароль | 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 "Ожирение"
Разделы выходных данных: Недостаточный вес, Норма, Избыточный вес, Ожирение. Подберите один вход, который активирует каждый выход.
Типичные ошибки
- Пропуск «пустого» класса. Всегда рассматривайте пустую строку, null или ноль как отдельный класс.
- Игнорирование типов данных. Числовое поле может получить буквы — это отдельный невалидный класс.
- Пересекающиеся классы. Каждое значение должно принадлежать ровно одному классу. Если классы пересекаются, разбиение выполнено неверно.
- Слишком мало невалидных классов. Обычно невалидных классов больше, чем валидных.
Упражнение: Спроектируйте классы эквивалентности
Сценарий: Система бронирования авиабилетов принимает следующие входные данные:
- Пассажиры: 1–9 (целое число)
- Класс: Economy, Business, First
- Тип поездки: В одну сторону, Туда и обратно
Задание: Определите все классы эквивалентности для каждого параметра и напишите минимальный набор тест-кейсов.
Подсказка
Для Пассажиров: подумайте, что происходит с 0, отрицательными числами, 10+, дробными числами и нечисловым вводом.
Для Класса и Типа поездки: каждый допустимый вариант — отдельный класс. А что с вариантом, которого не существует?
Решение
Пассажиры:
| # | Класс | Представитель | Валидный? |
|---|---|---|---|
| 1 | 1–9 | 4 | Да |
| 2 | < 1 | 0 | Нет |
| 3 | > 9 | 15 | Нет |
| 4 | Не целое число | 2.5 | Нет |
| 5 | Нечисловой | “abc” | Нет |
Класс обслуживания:
| # | Класс | Представитель | Валидный? |
|---|---|---|---|
| 6 | Economy | Economy | Да |
| 7 | Business | Business | Да |
| 8 | First | First | Да |
| 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-параметрам и заголовкам.