Зачем это спрашивают
Классы эквивалентности и граничные значения — две самые используемые техники тест-дизайна. Почти любое поле ввода, параметр запроса или настройка проверяется с их помощью, поэтому интервьюер почти наверняка спросит о них на позицию junior и проверит глубину на позицию middle.
Обычно вопрос идёт в два захода: сначала определение, потом живая задача вроде «поле принимает от 1 до 100, какие значения вы проверите?». По ответу на задачу видно главное: думаете ли вы о невалидных данных и понимаете ли, что границы есть не только у чисел.
Как построить сильный ответ
Классы эквивалентности
Класс эквивалентности — группа входных значений, на которых система ведёт себя одинаково. Раз поведение одинаковое, достаточно проверить одного представителя класса, а не все значения подряд. Так техника сокращает число проверок.
Ключевое — выделять не только валидный класс. Для поля «возраст от 18 до 65» классов больше, чем кажется:
- валидный: целые числа от 18 до 65;
- невалидные: меньше 18, больше 65;
- невалидные по типу: буквы, спецсимволы, дробное число, пустое поле, пробелы.
Каждый невалидный класс проверяют отдельно. Если в одном тесте смешать две ошибки, например пустое имя и неверный возраст, сообщение об одной может скрыть отсутствие проверки другой.
Граничные значения
Граница — край класса эквивалентности. На краях ошибаются чаще всего: перепутан строгий и нестрогий знак сравнения или допущена ошибка на единицу. Поэтому значения берут на самой границе и вплотную к ней.
Для диапазона от 1 до 100 есть две распространённые схемы:
| Схема | Нижняя граница | Верхняя граница |
|---|---|---|
| Двухзначная | 0, 1 | 100, 101 |
| Трёхзначная | 0, 1, 2 | 99, 100, 101 |
Двухзначная схема берёт саму границу и ближайшее значение по другую сторону. Трёхзначная добавляет соседа внутри класса. Назовите обе и скажите, какую выбираете и почему: трёхзначная надёжнее ловит ошибки в условии сравнения, двухзначная экономнее.
К границам добавьте представителей невалидных классов: пусто, отрицательное число, дробное, буквы, пробелы вокруг числа, очень большое число, которое может не поместиться в тип данных.
Границы есть не только у чисел
Это то, чем ответ middle отличается от ответа junior:
- Строка: длина 0, 1, максимум, максимум плюс один; формат; пробелы в начале и конце; символы юникода и эмодзи, которые могут занимать больше одного байта или кодовой единицы.
- Список или коллекция: пустой, один элемент, максимум, больше максимума.
- Дата: последний день месяца, 29 февраля в високосный и невисокосный год, переход через Новый год, переход на летнее время, если система работает в часовом поясе, где он действует.
- Деньги: 0, минимальная единица (0.01), отрицательная сумма, максимум, округление копеек при расчёте скидки.
Пример ответа
Класс эквивалентности — это группа значений, на которых система ведёт себя одинаково, поэтому из каждого класса достаточно одного представителя. Я обязательно выделяю невалидные классы: значения за диапазоном, пустое поле, буквы, дробные числа. Граничные значения — края этих классов, там ошибки встречаются чаще всего из-за неверного знака сравнения. Если поле принимает от 1 до 100, по трёхзначной схеме я проверю 0, 1, 2 и 99, 100, 101, а ещё пустое значение, отрицательное, дробное, буквы и очень большое число. Границы есть не только у чисел: у строки это длина 0, 1, максимум и максимум плюс один, у даты — конец месяца и 29 февраля, у денег — 0, 0.01 и округление.
Частые ошибки
- Ответ «1, 50, 100». Значение 50 ничего не говорит о границах, а 0 и 101 пропущены — как раз те, где обычно прячется ошибка.
- Только валидный класс. Без невалидных классов половина проверок теряется.
- Границы только у чисел. Строки, даты, списки и суммы — такие же кандидаты.
- Не уточнять требования. Включительно ли «до 100»? Принимаются ли дробные? Хороший кандидат задаёт эти вопросы, прежде чем выписывать значения.
- Смешивать несколько невалидных значений в одном тесте. Одно сообщение об ошибке может скрыть другое.
Пример на MarketCove
Допустим, по требованиям поле «Имя» в форме оформления заказа учебного магазина https://shop.tomiddle.com принимает от 2 до 50 символов (гипотетическое правило — в реальной задаче его уточняют у аналитика). Проверки по трёхзначной схеме плюс пустое значение удобно записать как параметризованный тест для API оформления заказа:
import pytest
@pytest.mark.parametrize(
("length", "accepted"),
[
(0, False), (1, False), (2, True), (3, True),
(49, True), (50, True), (51, False),
],
)
def test_order_name_length(api_client, order_payload, length, accepted):
payload = {**order_payload, "name": "а" * length}
response = api_client.post("/api/shop/orders", json=payload)
if accepted:
assert response.status_code in (200, 201)
else:
assert 400 <= response.status_code < 500
Здесь api_client и order_payload — фикстуры проекта (вторая собирает валидный заказ со всеми остальными полями), а имена полей условные: настоящую схему смотрите в Swagger на /api/docs. Обратите внимание на идею: проверка через API показывает, валидирует ли сервер длину сам, даже если интерфейс не даёт ввести 51 символ.
Длиной классы для имени не исчерпываются: добавьте строку из одних пробелов, имя с дефисом («Анна-Мария») и с буквой «ё» как валидных представителей, а цифры и спецсимволы — в тот класс, куда их отнесёт требование.
Задание для практики
Откройте форму оформления заказа в https://shop.tomiddle.com и выберите поле «Адрес». Выпишите классы эквивалентности: валидный и все невалидные, какие сможете придумать. Затем определите границы по длине и составьте список значений по трёхзначной схеме. Отдельно проверьте поведение через API в песочнице: совпадает ли валидация на сервере с ограничениями интерфейса. Итог проговорите вслух за полторы минуты.
