Критерии приёмки: как писать Given/When/Then, чтобы требование можно было проверить
Требование без критериев приёмки — это пожелание. «Пользователь должен иметь возможность отменить подписку» звучит понятно ровно до момента, когда разработчик спросит: а если она уже оплачена на месяц вперёд? А если платёж прямо сейчас в обработке? А если пользователь нажал «Отменить» дважды?
Критерии приёмки — это место, где требование превращается из намерения в проверяемое условие. Разберём, как их писать, чтобы тестировщик мог сделать из них тест-кейсы, не приходя к тебе за уточнениями.
Что это такое и зачем
🔤 Критерии приёмки (acceptance criteria, AC) — набор условий, при выполнении которых требование считается реализованным. Не «хорошо сделанным», а именно выполненным: это граница, по которой задачу принимают или возвращают.
Критерии решают три задачи сразу:
- Для разработчика — граница работы. Ясно, что входит в задачу, а что нет.
- Для тестировщика — основа тест-кейсов. Каждый критерий проверяется отдельно.
- Для заказчика — защита от «сделали не то». Он согласовал не идею, а конкретное поведение.
💡 Главный признак хорошего критерия: по нему можно однозначно сказать «да» или «нет», не споря. Если после прочтения двое понимают его по-разному — это ещё не критерий.
Два формата: сценарий и чек-лист
Форматов ровно два, и выбор между ними не дело вкуса.
Given/When/Then — сценарный формат. Подходит, когда важна последовательность: что-то произошло при определённых условиях и привело к результату.
Дано (Given): пользователь с активной подпиской «Про», оплаченной до 30.09
Когда (When): он подтверждает отмену подписки 22.09
Тогда (Then): подписка получает статус «отменена, активна до 30.09»,
автосписание отключено, доступ сохраняется до 30.09,
пользователю отправлено письмо с датой окончания
Чек-лист — список условий без сценария. Подходит для правил валидации, ограничений и требований к отображению.
- поле «Промокод» принимает от 4 до 20 символов: латиница, цифры, дефис
- регистр не учитывается: PROMO-10 и promo-10 — один и тот же код
- при вводе несуществующего кода поле подсвечивается, сумма не меняется
- истёкший код даёт отдельное сообщение: «Срок действия промокода истёк»
| Ситуация | Формат |
|---|---|
| Поведение системы в сценарии | Given/When/Then |
| Правила валидации поля | Чек-лист |
| Интеграция с внешним сервисом, ошибки и таймауты | Given/When/Then |
| Требования к отображению и содержанию экрана | Чек-лист |
| Права доступа по ролям | Чек-лист или таблица |
⚠️ Самая частая ошибка новичка — загонять в Given/When/Then то, где нет сценария. «Дано: пользователь на странице. Когда: он смотрит на поле. Тогда: поле не больше 20 символов» — это чек-лист, вывернутый наизнанку. Формат должен облегчать чтение, а не утяжелять.
Как разложить сценарий на три шага
Каждая часть отвечает на свой вопрос, и путают их постоянно.
Given — состояние до действия. Не действия пользователя, а именно состояние: какие данные есть в системе, в каком статусе объект, какие права у пользователя. Проверь себя: если в Given появился глагол «нажимает» — он попал не туда.
When — одно действие, запускающее сценарий. Именно одно. Два действия в When означают, что сценариев тоже два.
Then — наблюдаемый результат. Что изменилось так, что это можно увидеть или проверить: новый статус, отправленное письмо, запись в базе, сообщение на экране, вызов внешнего сервиса.
💡 Тест на наблюдаемость: «Тогда система корректно обрабатывает запрос» — не критерий, потому что «корректно» нельзя увидеть. «Тогда заказ переходит в статус paid, а пользователю показывается номер заказа» — критерий, потому что и статус, и номер проверяемы.
Пример: отмена подписки целиком
Возьмём одну user story и напишем к ней полный набор критериев. Сама история — по формату из статьи «Как писать user story»:
Как подписчик, я хочу отменить подписку, чтобы с меня перестали списывать деньги, но я доходил оплаченный период.
Сценарий 1. Отмена оплаченной подписки — основной путь
Дано: подписка в статусе «активна», оплачена до 30.09
Когда: пользователь подтверждает отмену 22.09
Тогда: статус меняется на «отменена»
дата окончания доступа — 30.09, доступ сохраняется
автопродление выключено
на почту уходит письмо с датой окончания
Сценарий 2. Отмена в первый день после оплаты
Дано: подписка оплачена сегодня, прошло меньше 24 часов
Когда: пользователь подтверждает отмену
Тогда: создаётся заявка на возврат полной суммы
статус — «отменена, возврат в обработке»
доступ закрывается сразу
Сценарий 3. Платёж в процессе
Дано: последний платёж в статусе «в обработке»
Когда: пользователь подтверждает отмену
Тогда: отмена не выполняется
показывается: «Дождись завершения платежа, обычно это минута»
кнопка отмены остаётся доступной
Сценарий 4. Повторный запрос отмены
Дано: подписка уже в статусе «отменена»
Когда: приходит ещё один запрос на отмену (двойной клик, повтор из письма)
Тогда: состояние не меняется, второй возврат не создаётся
ответ такой же, как на первый запрос
Сценарий 5. Платёжный сервис недоступен при возврате
Дано: подписка отменена в первые 24 часа, создана заявка на возврат
Когда: платёжный сервис отвечает ошибкой или не отвечает 30 секунд
Тогда: заявка остаётся в статусе «возврат в обработке»
запрос повторяется автоматически, но не чаще раза в 5 минут
пользователю видно: «Возврат оформляется, обычно до 5 рабочих дней»
дубль возврата не создаётся
Чек-лист к экрану отмены
- перед отменой показывается дата, до которой сохранится доступ
- есть явное подтверждение: отмена не происходит по одному клику
- в тексте нет слов «удалить» и «заблокировать» — это отмена, данные сохраняются
- после отмены на экране есть кнопка «Возобновить подписку»
Пять сценариев вместо одного — не педантизм. Первый сценарий очевиден всем. Остальные четыре — это как раз те случаи, которые в проде всплывают через неделю после релиза как баги.
Негативные сценарии, о которых забывают чаще всего
Если не знаешь, с чего начать перебор, пройди по этому списку. Он закрывает большую часть пропусков.
| Класс | Вопрос к требованию |
|---|---|
| Повтор действия | Что если запрос придёт дважды? Дубль создастся? |
| Гонка состояний | Что если статус изменился, пока пользователь смотрел на экран? |
| Внешняя система молчит | Что показываем, если сервис не ответил за N секунд? |
| Частичный успех | Деньги списались, а заказ не создался — что дальше? |
| Пустые данные | Как выглядит экран, когда записей ноль? |
| Границы | Минимум, максимум, ноль, отрицательное значение, очень длинная строка |
| Права | Что видит пользователь, у которого нет доступа? Ошибку или «не найдено»? |
| Время | Что происходит ровно в момент окончания периода? Какая таймзона? |
| Отмена на полпути | Пользователь закрыл вкладку посередине — что осталось в системе? |
⚠️ Отдельно про деньги и статусы: если в требовании есть хоть одна денежная операция, критерии на повтор запроса и на недоступность платёжного сервиса обязательны. Это два самых дорогих дефекта, и оба молчаливые — система работает, логи чистые, суммы неверные. На собеседовании про идемпотентность спрашивают именно поэтому (см. разбор вопросов для джуна).
Девять ошибок, из-за которых критерий не работает
- Нельзя проверить. «Система работает быстро» → «страница отдаёт ответ не дольше 2 секунд при 100 одновременных пользователях».
- Описано решение, а не поведение. «Добавить поле в таблицу
orders» — это задача разработчику, а не критерий приёмки. Критерий говорит, что должно произойти, а не как это реализовать. - Только счастливый путь. Один сценарий на требование — почти всегда признак, что негативные случаи не продумывали.
- Две проверки в одном критерии. «Заказ создаётся и письмо отправляется» — при падении письма непонятно, критерий провален или нет. Разделяй.
- Скрытое «и/или». «Пользователь видит ошибку или письмо не отправляется» — два разных поведения в одной строке.
- Размытые слова. «Корректно», «удобно», «при необходимости», «и т.п.». Каждое из них означает «мы ещё не решили».
- Нет состояния в Given. «Дано: пользователь» — а какой? С подпиской, без, с истёкшей, заблокированный? Половина дефектов рождается здесь.
- Критерии противоречат друг другу. В одном доступ закрывается сразу, в другом — до конца периода. Проверяй пачку целиком, а не по одному.
- Критерии приёмки перепутаны с Definition of Done. AC описывают поведение конкретного требования. DoD — это общие правила команды (код отревьюен, тесты написаны, документация обновлена), они одинаковы для всех задач и в критерии не входят.
Чек-лист самопроверки
Перед тем как отдать требование в работу, пройди по шести пунктам:
- Каждый критерий проверяется ответом «да» или «нет», без обсуждения.
- Есть хотя бы один негативный сценарий и один про повтор действия.
- В Given описано состояние, а не действие.
- В When ровно одно действие.
- В Then — только наблюдаемые изменения: статус, сообщение, письмо, запись, вызов.
- Нет слов «корректно», «удобно», «оптимально», «при необходимости».
И финальная проверка, которая работает лучше всех остальных: дай критерии тестировщику и спроси, сколько тест-кейсов он из них сделает. Если он начинает задавать уточняющие вопросы — эти вопросы и есть твои пробелы. Если молча уходит писать тесты — критерии готовы.
Итог
- Критерии приёмки — граница между «реализовано» и «нет». Без них требование остаётся пожеланием.
- Два формата: Given/When/Then для сценариев, чек-лист для правил и валидаций. Не путать.
- Given — состояние, When — одно действие, Then — наблюдаемый результат.
- Один счастливый путь — это не критерии. Негативные сценарии, повторы и недоступность внешних систем — обязательная часть.
- Размытые слова в критериях означают нерешённый вопрос, который всплывёт на приёмке.
- AC — про поведение конкретного требования, DoD — про правила команды; смешивать их не нужно.
Писать критерии учатся не по статьям, а на обратной связи: пока кто-то не покажет дыру в твоём сценарии, она не видна. В курсе «Аналитик.Старт» требования к сквозному кейсу — платной подписке с оплатой картой — пишутся именно так: с негативными сценариями, идемпотентностью и разбором того, что упущено, против эталона. Первые блоки открыты бесплатно.