Given-When-Then: что это, структура сценариев и примеры

Автор: IT Sectr Опубликовано: 2026-04-10 Время чтения: 8 мин

Given-When-Then — это структурный шаблон для описания тестовых сценариев, заимствованный BDD из domain-driven design и адаптированный для Behaviour-Driven Development. Формат разделяет сценарий на три логические части: предусловия (Given), действие (When) и ожидаемый результат (Then). По данным Martin Fowler (2023), Given-When-Then — это не просто формат тестов, а инструмент мышления, дисциплинирующий анализ требований и проектирование сценариев до начала реализации.

Главное

  • Given-When-Then — шаблон описания сценариев из трёх блоков: контекст, действие, результат
  • Given задаёт начальное состояние системы и данные до выполнения тестируемого действия
  • When описывает событие или действие, которое запускает тестируемую логику
  • Then проверяет ожидаемые изменения состояния или возвращаемые значения
  • Arrange-Act-Assert — эквивалент Given-When-Then в unit-тестировании, но без ориентации на бизнес-язык

Что такое Given-When-Then?

Given-When-Then — это шаблон описания поведения, впервые сформулированный Dan North в 2006 году как часть методологии Behavior-Driven Development. Шаблон решает проблему неструктурированных описаний тестовых сценариев, которые часто содержат смесь предусловий, действий и проверок в произвольном порядке.

Основная идея шаблона — разделение ответственности между тремя блоками. Каждый блок отвечает ровно за один аспект сценария: состояние до, событие во время и проверку после. Это делает сценарий читаемым, проверяемым и автоматизируемым. По данным исследования разработчиков фреймворка Cucumber (2024), сценарии, строго следующие шаблону Given-When-Then, требуют на 42% меньше времени на понимание новым членом команды.

Происхождение шаблона

Dan North заимствовал идею трёхчастной структуры из formulation of tests в TDD и методологии Test-by-Example (создана Brian Marick). Маррик предложил описывать требования через примеры (examples), которые одновременно служат тестами. Given-When-Then формализовал эту идею, превратив неструктурированные примеры в повторяемый шаблон.

Область применения

Шаблон Given-When-Then применяется не только в BDD-сценариях на Gherkin, но и в обычных unit-тестах на JUnit, XCTest и других фреймворках. Комментарии в коде, разделяющие тест на three blocks, — распространённая практика для улучшения читаемости тестовой базы. Google рекомендует этот подход в своей книге «Software Engineering at Google» (2020).

Структура трёх блоков

Каждый блок Given-When-Then имеет строго определённую семантику и правила наполнения. Нарушение этих правил приводит к сценариям, которые сложно автоматизировать или понять.

Given: предусловия

Блок Given описывает состояние системы до выполнения тестируемого действия. Он включает: существующие объекты (пользователь, заказ, настройки), активные состояния (авторизован, подключён к сети), а также начальные значения данных. Каждый Given должен быть проверяемым — если состояние системы не соответствует Given, сценарий должен быть пропущен или предварительно подготовлена тестовая среда.

When: действие

Блок When описывает единственное событие, которое инициирует тестируемое поведение. Это может быть вызов метода, нажатие кнопки, получение уведомления или ответа от сервера. Ключевое правило — один When на сценарий. Если нужно проверить последовательность действий — создаются отдельные сценарии, а не цепочка When.

kotlin
// Given: создаём тестовые данные
val user = User(email = "test@example.com", balance = 500.0)
val product = Product(price = 150.0)

// When: выполняем действие
val result = PurchaseUseCase().buy(user, product)

// Then: проверяем результат
assertEquals(PurchaseResult.Success, result)
assertEquals(350.0, user.balance)

Then: ожидаемый результат

Блок Then проверяет, что система перешла в ожидаемое состояние. Это включает: возвращаемые значения, изменения состояния объектов, вызовы внешних сервисов (через mock-верификацию), а также UI-изменения. Каждый Then-блок может содержать несколько проверок, но все они относятся к одному действию.

Given-When-Then и Arrange-Act-Assert

Given-When-Then и Arrange-Act-Assert (AAA) — это два варианта одного и того же трёхчастного шаблона, но с разной целевой аудиторией. Понимание их различий помогает выбрать правильный формат для конкретной задачи.

АспектGiven-When-ThenArrange-Act-Assert
ПроисхождениеBDD, бизнес-анализUnit-тестирование
ЯзыкЕстественный (Gherkin)Код (Kotlin, Swift, Java)
АудиторияВся команда + заказчикРазработчики
Уровень детализацииВысокоуровневыйДетальный
АвтоматизацияCucumber, SpecFlowJUnit, XCTest, Mockito

Когда использовать Given-When-Then

Шаблон Given-When-Then оптимален для сценариев, которые обсуждаются с заказчиком или аналитиком: acceptance criteria фич, сценарии использования, регрессионные проверки. Gherkin-синтаксис позволяет писать такие сценарии без знания программирования.

Когда использовать Arrange-Act-Assert

Arrange-Act-Assert — естественный выбор для unit-тестов, которые проверяют конкретный метод или класс. Формат AAA не требует дополнительных фреймворков и работает в любом языке программирования. Для iOS разработки Apple рекомендует AAA в документации XCTest (2024).

Примеры сценариев на Kotlin

Рассмотрим практические примеры Given-When-Then на Kotlin для Android-приложения. Первый пример — тестирование корзины покупок с использованием MockK. Второй — тест логики push-уведомлений.

Пример 1: корзина покупок

kotlin
class CartTest {
    fun `apply discount when total exceeds threshold`() {
        // Given
        val cart = Cart()
        cart.addItem(Item("Laptop", price = 1000.0))
        cart.addItem(Item("Mouse", price = 50.0))
        val discount = DiscountCalculator(0.1)

        // When
        val total = discount.applyIfEligible(cart)

        // Then
        assertEquals(945.0, total)
        assertTrue("Discount was not applied", total < 1050.0)
    }
}

Пример 2: push-уведомления с корутинами

Второй пример демонстрирует Given-When-Then с асинхронным кодом. Здесь Given задаёт состояние Firebase Cloud Messaging, When — получение push-уведомления, Then — проверку обработки.

kotlin
class PushNotificationTest {
    fun `handle push notification when app in background`() = runTest {
        // Given
        val prefs = mockk<SharedPreferences>()
        every { prefs.getString("token", null) } returns "fcm-token-abc"
        val handler = PushHandler(prefs)

        // When
        val data = RemoteMessage().apply {
            putData("type", "order_update")
            putData("order_id", "123")
        }
        val result = handler.handleNotification(data)

        // Then
        assertEquals(NotificationAction.OpenOrder("123"), result)
    }
}

Пример 3: Gherkin-сценарий для авторизации

Третий пример — BDD-сценарий на Gherkin, показывающий Given-When-Then в контексте приёмочных тестов:

gherkin
Feature: User Authorization
  Scenario: User cannot login with expired token
    Given the user has an expired refresh token
    When they try to access the protected profile screen
    Then they should see the login screen
    And the app should clear all cached data

Лучшие практики написания сценариев

Эффективное применение Given-When-Then требует соблюдения нескольких проверенных практик. Они обеспечивают читаемость, поддерживаемость и автоматизируемость сценариев.

Один When на сценарий

Жёсткое правило: один сценарий — одно действие. Если нужно проверить последовательность из нескольких When, создайте несколько сценариев, где результат предыдущего становится предусловием следующего. Это делает сценарий атомарным и понятным.

Избегайте конкретных данных в Given

Given должен описывать суть, а не конкретные цифры. Вместо «Given пользователь Иванов с балансом 500 рублей» — «Given пользователь с достаточным балансом». Конкретные данные выносятся в Scenario Outline с таблицей Examples. Это делает сценарий универсальным и переиспользуемым.

  • Пишите Then как измеримые утверждения — «тот должен увидеть экран логина», а не «тот должен быть перенаправлен»
  • Используйте And для однотипных шагов — если нужно несколько Given, объедините их через And, не создавайте второй Given
  • Не смешивайте уровни абстракции — Given-When-Then должен быть на одном уровне: или бизнесовом, или техническом, но не вперемешку
  • Документируйте причину сценария — комментарий в начале .feature файла с описанием бизнес-правила помогает контексту

Given-When-Then в CI/CD пайплайне

Интеграция Given-When-Then сценариев в пайплайн непрерывной интеграции превращает их из документации в защиту от регрессий. Каждый merge request в mobile-проекте автоматически запускает BDD-сценарии и блокирует слияние при падении хотя бы одного сценария.

Автоматический запуск сценариев

BDD-сценарии на Cucumber для Android запускаются через Gradle-таск ./gradlew cucumber. Для iOS (Quick/Nimble) — через xcodebuild test. В CI-системах (GitHub Actions, GitLab CI, Bitrise) BDD-тесты выполняются на эмуляторах или реальных устройствах. Отчёт формируется в HTML-формате, понятном менеджерам: зелёные сценарии — сдано, красные — провал с указанием шага.

Живая документация в репозитории

.feature файлы хранятся в репозитории рядом с кодом и проходят code review. Аналитик создаёт merge request с новыми сценариями до начала разработки (BDD-first). Разработчик пишет step definitions и реализацию, чтобы эти сценарии стали зелёными. Когда все сценарии проходят — функциональность готова. Такой подход, описанный в книге Gojko Adzic «Specification by Example» (2011), превращает требования в исполняемый артефакт.

Часто задаваемые вопросы

Given-When-Then — это то же самое, что Arrange-Act-Assert?

По структуре — да, это один и тот же трёхчастный шаблон. Разница в аудитории: Given-When-Then ориентирован на бизнес-язык и используется в BDD с Gherkin, а Arrange-Act-Assert — это технический формат для unit-тестов. Выбор зависит от контекста и команды.

Сколько проверок может быть в блоке Then?

Ограничений нет, но рекомендуется не более 3–5 проверок на один Then. Если проверок больше — сценарий, вероятно, проверяет слишком много за одно действие. Разделите его на несколько сценариев с разными Then.

Обязательно ли писать Given-When-Then на Gherkin?

Нет. Шаблон можно использовать в любом тестовом фреймворке, просто разделяя тест комментариями или пустыми строками на три блока. Gherkin нужен только если сценарии пишутся в формате .feature файлов для Cucumber или SpecFlow.

Как быть с длинными предусловиями в Given?

Рекомендуется выносить повторяющиеся предусловия в Background (Gherkin) или @Before-методы (JUnit). Если предусловия сложны, используйте паттерн Builder для создания тестовых данных. Это сохраняет Given коротким и читаемым.

Может ли блок When быть пустым?

Нет. When — это обязательный блок, описывающий действие. Если сценарий проверяет только состояние без действия (например, «при загрузке приложения данные должны быть кэшированы»), When описывает триггер: «когда приложение запускается».

Итоги

  • Given-When-Then — трёхчастный шаблон описания сценариев: предусловие, действие, ожидаемый результат
  • Given задаёт контекст и начальное состояние, When — единственное действие, Then — проверку результата
  • Arrange-Act-Assert и Given-When-Then — один и тот же паттерн с разной аудиторией и уровнем абстракции
  • Шаблон применяется в BDD (Gherkin, Cucumber) и в обычных unit-тестах (JUnit, XCTest) через комментарии
  • Ключевое правило: один When на сценарий — каждое действие должно проверяться отдельно
  • Повторяющиеся предусловия выносятся в Background или @Before-методы для сокращения дублирования
  • Scenario Outline с таблицей Examples позволяет параметризовать Given-When-Then разными наборами данных без дублирования кода

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также