Сквозной пример: тестируем форму регистрации

Берём одну скромную форму на четыре поля и проходим по ней весь маршрут тестировщика — от вопросов аналитику до баг-репорта, который починят.

Сквозной пример (end-to-end) — прогон одной небольшой функции через весь цикл работы тестировщика: разбор требований, чек-лист, тест-дизайн, выполнение проверок и оформление найденных дефектов.

До сих пор техники жили по отдельности: в одном уроке классы эквивалентности, в другом — баг-репорт, в третьем — DevTools. На собеседовании и на работе от вас ждут другого: чтобы вы взяли требование и превратили его в набор проверок, а потом в понятный отчёт. Именно этот переход и вызывает ступор у новичков — техники вроде знакомы, а с чего начать на живой задаче, непонятно.

Поэтому давайте сделаем это вместе. Наш объект — форма регистрации в интернет-магазине. Четыре поля, одна кнопка. Кажется, там нечего тестировать. Сейчас увидим, что там прячется десяток багов и целая пачка неотвеченных вопросов.

Шаг 0. Читаем требования и ищем в них дыры

Вот всё, что нам передал аналитик. Такое требование — не карикатура, это типичный уровень детализации в реальном спринте.

ФТ-14. Форма регистрации

Поля: Email, Пароль, Возраст, чекбокс «Согласен с условиями».

1. Email обязателен, должен быть валидным.
2. Пароль: от 8 до 20 символов, минимум одна цифра и одна заглавная буква.
3. Возраст: от 18 до 65.
4. Кнопка «Зарегистрироваться» активна, только если поля заполнены.
5. После успешной регистрации пользователь получает письмо
   и попадает в личный кабинет.

Первый рефлекс новичка — сразу открыть форму и начать кликать. Первый рефлекс инженера — задать вопросы. Тестирование начинается с требований, а не с приложения: если в требовании дыра, то и в ваших проверках будет ровно та же дыра, и баг спокойно доедет до продакшена — уже не как баг, а как «мы так и задумывали, наверное».

ПунктЧто недосказаноВопрос аналитику
1. «Валидный email»Валидный по какому правилу? Адреса вида ivan+shop@mail.ru, домены на кириллице, длина под 300 символовКакие адреса считаем валидными? Регистр важен: Ivan@mail.ru и ivan@mail.ru — один пользователь или два?
2. «От 8 до 20»Границы включительно? Пробел — это символ? Что при вставке 25 символов: ошибка или обрезка?8 и 20 допустимы? Что делаем с пробелами в начале и конце?
3. «Возраст 18–65»18 и 65 включительно? Пользователь вводит число или дату рождения (тогда возраст считает система)?Границы включительно? Как ведём себя при вводе 17: блокируем кнопку или показываем ошибку?
4. «Поля заполнены»Чекбокс входит в «поля»? Кнопка активна при заполненных, но невалидных данных?Согласие обязательно? Что показываем, если поля заполнены мусором?
5. «Получает письмо»Письмо уходит синхронно? Что если почтовый сервис недоступен?Регистрация должна упасть, если письмо не ушло, или пройти и отправить письмо позже?
Нет вовсеПовторная регистрация на существующий email; ограничение частоты попытокЧто показываем при регистрации на уже занятый email?

Три вопроса, заданные до начала тестирования, экономят три дня переписки в баг-трекере. И, кстати, это ровно тот навык, который проверяют на собеседовании задачей «протестируй карандаш»: смотрят не на список проверок, а на то, спросите ли вы про контекст.

Шаг 1. Чек-лист: карта территории

Чек-лист отвечает на вопрос «что вообще будем проверять», без деталей. Он нужен, чтобы ничего не забыть и чтобы увидеть объём работы. Детали появятся на следующем шаге.

  • Интерфейс: все поля на месте, подписи и плейсхолдеры без опечаток; вёрстка не разъезжается на 360px и при масштабе 200%; переход по Tab идёт сверху вниз; форму можно отправить с клавиатуры (Enter).
  • Позитивный сценарий: валидные данные → аккаунт создан, письмо пришло, пользователь в личном кабинете, запись появилась в базе.
  • Валидация полей: email, пароль, возраст, чекбокс — по классам эквивалентности и границам (шаг 2).
  • Негатив и устойчивость: пустые поля, пробелы, спецсимволы, длинные строки, двойной клик, обрыв сети (шаг 3).
  • Данные и интеграции: повторная регистрация того же email, письмо реально уходит, пароль не хранится и не передаётся в открытом виде, в ответе сервера нет лишних данных.
  • Кросс-проверки: Chrome / Safari / мобильный браузер; автозаполнение и вставка из буфера; кнопка «Назад» после успешной регистрации.

Шесть строк — а работы уже на день. Это нормально: чек-лист честно показывает объём, и с ним можно идти к тимлиду обсуждать приоритеты.

Шаг 2. Классы эквивалентности и границы

Наивный перебор по трём полям даёт сотни комбинаций. Тест-дизайн сжимает их до осмысленного минимума: делим значения на классы, где система ведёт себя одинаково, берём по одному представителю от класса и отдельно щупаем границы — там живёт большинство багов.

ПолеКлассПредставительОжидаемое поведение
ВозрастМеньше минимума17Ошибка «Регистрация с 18 лет»
ВозрастДопустимый диапазон30Принять
ВозрастБольше максимума66Ошибка
ВозрастНе число / мусор-5, 18.5, «тридцать»Ошибка, форма не отправляется
ПарольКороче 8Qwerty1Ошибка о длине
ПарольДлина ок, но нет цифрыQwertyuioОшибка о составе
ПарольДлина ок, но нет заглавнойqwerty123Ошибка о составе
ПарольВалидныйQwerty123Принять
EmailВалидныйivan@mail.ruПринять
EmailНет собаки / нет доменаivan.mail.ru, ivan@Ошибка
EmailУже зарегистрированivan@mail.ru (повторно)Понятное сообщение, не 500-я ошибка

Границы проверяются тремя точками: значение до границы, сама граница и значение сразу за ней. Одной точки мало — классическая ошибка разработчика if (len > 8) вместо if (len >= 8) ловится только так. Вот генератор таких точек для правила «пароль 8–20 символов» — можете нажать «Запустить» и посмотреть, какие ровно шесть проверок нужны на одно поле.

MIN_LEN, MAX_LEN = 8, 20

cases = [
    ("ниже границы", MIN_LEN - 1),
    ("нижняя граница", MIN_LEN),
    ("сразу после", MIN_LEN + 1),
    ("перед верхней", MAX_LEN - 1),
    ("верхняя граница", MAX_LEN),
    ("выше границы", MAX_LEN + 1),
]

for name, length in cases:
    verdict = "принять" if MIN_LEN <= length <= MAX_LEN else "отклонить"
    print(f"len={length:>2} — {name:<15} → ожидаем: {verdict}")

Результат:

len= 7 — ниже границы    → ожидаем: отклонить
len= 8 — нижняя граница  → ожидаем: принять
len= 9 — сразу после     → ожидаем: принять
len=19 — перед верхней   → ожидаем: принять
len=20 — верхняя граница → ожидаем: принять
len=21 — выше границы    → ожидаем: отклонить

Шаг 3. Негативные сценарии: включаем «злого тестировщика»

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

ПриёмЧто вводим / делаемЧто на самом деле проверяем
Пустота и пробелыТри пробела в поле emailОбрезаются ли пробелы (trim) или считаются заполнением
Длинная строкаEmail на 1000 символовНе рвётся ли вёрстка, нет ли ошибки 500 на сервере
Спецсимволы' OR 1=1 -- и <script>alert(1)</script>Экранируются ли данные; не выполняется ли чужой код
ЮникодЭмодзи в пароле, кириллица в возрастеКодировка, подсчёт длины, адекватная ошибка вместо падения
Двойной кликБыстро дважды жмём «Зарегистрироваться»Не создастся ли два аккаунта и два письма
Обрыв сетиDevTools → Network → Offline в момент отправкиПонятная ошибка вместо вечного спиннера; можно ли повторить
Вставка из буфераКопипастим пароль вместо набораРаботают ли валидация и ограничения при вставке (частый баг!)
Кнопка «Назад»После регистрации возвращаемся браузером назадНе отправится ли форма повторно

Обратите внимание на строку про буфер обмена. Именно там мы сейчас и поймаем баг.

Шаг 4. Нашли баг — оформляем так, чтобы починили

Вставляем в поле пароля 25-символьную строку из менеджера паролей. Форма молча принимает её, показывает 20 символов-звёздочек, регистрация проходит успешно. А потом мы выходим и пытаемся войти с тем паролем, который вставляли, — и не можем. Смотрим в DevTools, вкладка Network, и видим в запросе к серверу уже обрезанное значение.

POST /api/v1/register  →  201 Created

Запрос (Request payload):
{
  "email": "ivan@mail.ru",
  "password": "Qwerty1234567890Abcd",   ← 20 символов вместо вставленных 25
  "age": 30
}

Это не косметика: пользователь физически не может войти в свой аккаунт, и без обращения в поддержку он не поймёт почему. Оформляем.

Заголовок:
[Регистрация] Пароль длиннее 20 символов молча обрезается —
после регистрации вход с исходным паролем невозможен

Окружение:
Stage 2.14.0, Chrome 126, Windows 11, разрешение 1920x1080

Предусловие:
Пользователь не зарегистрирован, email ivan@mail.ru свободен

Шаги воспроизведения:
1. Открыть /register
2. Ввести email: ivan@mail.ru
3. Вставить из буфера пароль из 25 символов:
   Qwerty1234567890AbcdEfghi
4. Указать возраст 30, отметить чекбокс согласия
5. Нажать «Зарегистрироваться»
6. Выйти из аккаунта и войти с паролем из шага 3

Фактический результат:
На шаге 3 поле принимает только первые 20 символов, ошибка не показана.
В запросе POST /api/v1/register уходит обрезанный пароль (см. вложение).
На шаге 6 вход не выполняется: «Неверный email или пароль».

Ожидаемый результат:
Либо форма показывает ошибку «Пароль не должен быть длиннее 20 символов»
и не отправляет данные, либо принимает пароль целиком (по ФТ-14 п.2 —
уточнено с аналитиком: показываем ошибку).

Severity: Critical — пользователь теряет доступ к созданному аккаунту
Priority: High — затрагивает всех, кто пользуется менеджером паролей

Вложения: скриншот формы, HAR-файл, скриншот вкладки Network
Дополнительно: на поле стоит атрибут maxlength=20 — обрезка происходит
на фронтенде, до отправки запроса.

Разберём, что делает этот репорт хорошим. В заголовке сразу видно, что сломано и чем это грозит — тимлид приоритизирует его, не открывая. Шаги воспроизведения точные, с конкретными данными: другой человек повторит их с первого раза. Фактический результат отделён от ожидаемого, и ожидаемый подкреплён ссылкой на требование — это защищает от спора «а так и должно быть». Severity Critical (техническая тяжесть: доступ потерян) и Priority High (бизнес-срочность) выставлены осознанно и по отдельности. А последняя строка про maxlength=20 — это уже подарок разработчику: вы не просто нашли симптом, вы показали, где искать причину.

Как это работает

Обратите внимание на форму всего процесса — это воронка, которая сужается на каждом шаге:

  1. Требования дают предмет разговора — и сразу порождают вопросы, а не тесты.
  2. Чек-лист отвечает на вопрос «ЧТО проверяем» и фиксирует объём.
  3. Техники тест-дизайна отвечают на «КАКИМИ значениями» и сжимают сотни комбинаций до пары десятков осмысленных.
  4. Прогон превращает кейсы в наблюдения — и обязательно с открытыми DevTools, иначе половина причин остаётся невидимой.
  5. Баг-репорт превращает наблюдение в задачу для разработчика.

Каждый следующий шаг опирается на предыдущий. Пропустите первый — и получите красивые тест-кейсы не на ту систему. Пропустите третий — утонете в бесконечном переборе. Пропустите последний — ваш баг просто не починят.

И ещё одно наблюдение, ради которого стоило проходить весь путь: баг мы нашли не в поле «возраст», где очевидные границы 18 и 65, а на стыке — при вставке из буфера. Так бывает почти всегда. Одиночные поля разработчик проверяет сам; ломается система там, где сходятся два механизма (валидация + буфер обмена, фронтенд + бэкенд, форма + повторная отправка). Именно поэтому негативные сценарии и стыки — самая доходная часть работы тестировщика.

Частые ошибки

  • Начинать с кликов, а не с требований. Если требование дырявое, тесты унаследуют ту же дыру, и никто не заметит пропажу.
  • Проверять границу одной точкой. Ввели 18 — работает, пошли дальше. Ошибка > вместо >= при этом остаётся живой.
  • Тестировать «как пользователь», не открывая DevTools. Вы увидите симптом, но не поймёте, чья это вина — фронта или бэка, и репорт получится беспомощным.
  • Верить интерфейсу. Надпись «Регистрация успешна» не означает, что запись появилась в базе, а письмо ушло. Проверяйте результат там, где он должен быть.
  • Один баг на всё. Репорт «форма регистрации работает плохо» с пятью проблемами внутри невозможно ни приоритизировать, ни закрыть.
  • Не фиксировать окружение и версию. Ответ «у меня не воспроизводится» стоит вам дня жизни.
  • Останавливаться на позитивном сценарии. Он проверяет, что система умеет работать. Баги живут в том, чего вы ещё не пробовали.

Итоги

  • Тестирование начинается с требований: сначала вопросы аналитику, потом проверки.
  • Чек-лист отвечает на «что проверяем», тест-дизайн — на «какими значениями».
  • Каждую границу щупаем тремя точками: до, на границе, сразу после.
  • Негативные сценарии и стыки механизмов приносят больше багов, чем аккуратный позитивный путь.
  • Хороший баг-репорт: говорящий заголовок, точные шаги, разделённые фактический и ожидаемый результат, окружение, осознанные severity и priority, подсказка о причине.
  • Открытые DevTools во время прогона — разница между «что-то не работает» и «фронтенд обрезает пароль до отправки запроса».
Проверьте себя
1. В требовании написано: «Возраст: от 18 до 65». С чего правильнее начать работу?
AОткрыть форму и сразу проверить значения 18, 30 и 65
BУточнить у аналитика, включительны ли границы и что делаем при вводе 17, а уже потом составлять проверки
CНаписать 48 тест-кейсов — по одному на каждый допустимый возраст
DДождаться, пока разработчик расскажет, как он это реализовал
2. Форма молча обрезает вставленный пароль до 20 символов, регистрация проходит, но войти потом невозможно. Какие severity и priority уместны?
ASeverity: Minor, Priority: Low — это ведь косметика поля ввода
BSeverity: Critical, Priority: High — пользователь теряет доступ к созданному аккаунту, и это касается всех, кто вставляет пароль из менеджера
CSeverity: Critical, Priority: Critical — priority всегда совпадает с severity
DЭто не баг: требование про длину 8–20 символов формально соблюдено