Аналитик.старт
← Все статьи

Критерии приёмки: как писать 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 секунд?
Частичный успех Деньги списались, а заказ не создался — что дальше?
Пустые данные Как выглядит экран, когда записей ноль?
Границы Минимум, максимум, ноль, отрицательное значение, очень длинная строка
Права Что видит пользователь, у которого нет доступа? Ошибку или «не найдено»?
Время Что происходит ровно в момент окончания периода? Какая таймзона?
Отмена на полпути Пользователь закрыл вкладку посередине — что осталось в системе?

⚠️ Отдельно про деньги и статусы: если в требовании есть хоть одна денежная операция, критерии на повтор запроса и на недоступность платёжного сервиса обязательны. Это два самых дорогих дефекта, и оба молчаливые — система работает, логи чистые, суммы неверные. На собеседовании про идемпотентность спрашивают именно поэтому (см. разбор вопросов для джуна).

Девять ошибок, из-за которых критерий не работает

  1. Нельзя проверить. «Система работает быстро» → «страница отдаёт ответ не дольше 2 секунд при 100 одновременных пользователях».
  2. Описано решение, а не поведение. «Добавить поле в таблицу orders» — это задача разработчику, а не критерий приёмки. Критерий говорит, что должно произойти, а не как это реализовать.
  3. Только счастливый путь. Один сценарий на требование — почти всегда признак, что негативные случаи не продумывали.
  4. Две проверки в одном критерии. «Заказ создаётся и письмо отправляется» — при падении письма непонятно, критерий провален или нет. Разделяй.
  5. Скрытое «и/или». «Пользователь видит ошибку или письмо не отправляется» — два разных поведения в одной строке.
  6. Размытые слова. «Корректно», «удобно», «при необходимости», «и т.п.». Каждое из них означает «мы ещё не решили».
  7. Нет состояния в Given. «Дано: пользователь» — а какой? С подпиской, без, с истёкшей, заблокированный? Половина дефектов рождается здесь.
  8. Критерии противоречат друг другу. В одном доступ закрывается сразу, в другом — до конца периода. Проверяй пачку целиком, а не по одному.
  9. Критерии приёмки перепутаны с Definition of Done. AC описывают поведение конкретного требования. DoD — это общие правила команды (код отревьюен, тесты написаны, документация обновлена), они одинаковы для всех задач и в критерии не входят.

Чек-лист самопроверки

Перед тем как отдать требование в работу, пройди по шести пунктам:

  • Каждый критерий проверяется ответом «да» или «нет», без обсуждения.
  • Есть хотя бы один негативный сценарий и один про повтор действия.
  • В Given описано состояние, а не действие.
  • В When ровно одно действие.
  • В Then — только наблюдаемые изменения: статус, сообщение, письмо, запись, вызов.
  • Нет слов «корректно», «удобно», «оптимально», «при необходимости».

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

Итог

  • Критерии приёмки — граница между «реализовано» и «нет». Без них требование остаётся пожеланием.
  • Два формата: Given/When/Then для сценариев, чек-лист для правил и валидаций. Не путать.
  • Given — состояние, When — одно действие, Then — наблюдаемый результат.
  • Один счастливый путь — это не критерии. Негативные сценарии, повторы и недоступность внешних систем — обязательная часть.
  • Размытые слова в критериях означают нерешённый вопрос, который всплывёт на приёмке.
  • AC — про поведение конкретного требования, DoD — про правила команды; смешивать их не нужно.

Писать критерии учатся не по статьям, а на обратной связи: пока кто-то не покажет дыру в твоём сценарии, она не видна. В курсе «Аналитик.Старт» требования к сквозному кейсу — платной подписке с оплатой картой — пишутся именно так: с негативными сценариями, идемпотентностью и разбором того, что упущено, против эталона. Первые блоки открыты бесплатно.