Given-When-Then — это структурный шаблон для описания тестовых сценариев, заимствованный BDD из domain-driven design и адаптированный для Behaviour-Driven Development. Формат разделяет сценарий на три логические части: предусловия (Given), действие (When) и ожидаемый результат (Then). По данным Martin Fowler (2023), 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, сценарий должен быть пропущен или предварительно подготовлена тестовая среда.
Блок When описывает единственное событие, которое инициирует тестируемое поведение. Это может быть вызов метода, нажатие кнопки, получение уведомления или ответа от сервера. Ключевое правило — один When на сценарий. Если нужно проверить последовательность действий — создаются отдельные сценарии, а не цепочка When.
// 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 проверяет, что система перешла в ожидаемое состояние. Это включает: возвращаемые значения, изменения состояния объектов, вызовы внешних сервисов (через mock-верификацию), а также UI-изменения. Каждый Then-блок может содержать несколько проверок, но все они относятся к одному действию.
Given-When-Then и Arrange-Act-Assert (AAA) — это два варианта одного и того же трёхчастного шаблона, но с разной целевой аудиторией. Понимание их различий помогает выбрать правильный формат для конкретной задачи.
| Аспект | Given-When-Then | Arrange-Act-Assert |
|---|---|---|
| Происхождение | BDD, бизнес-анализ | Unit-тестирование |
| Язык | Естественный (Gherkin) | Код (Kotlin, Swift, Java) |
| Аудитория | Вся команда + заказчик | Разработчики |
| Уровень детализации | Высокоуровневый | Детальный |
| Автоматизация | Cucumber, SpecFlow | JUnit, XCTest, Mockito |
Шаблон Given-When-Then оптимален для сценариев, которые обсуждаются с заказчиком или аналитиком: acceptance criteria фич, сценарии использования, регрессионные проверки. Gherkin-синтаксис позволяет писать такие сценарии без знания программирования.
Arrange-Act-Assert — естественный выбор для unit-тестов, которые проверяют конкретный метод или класс. Формат AAA не требует дополнительных фреймворков и работает в любом языке программирования. Для iOS разработки Apple рекомендует AAA в документации XCTest (2024).
Рассмотрим практические примеры Given-When-Then на Kotlin для Android-приложения. Первый пример — тестирование корзины покупок с использованием MockK. Второй — тест логики push-уведомлений.
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)
}
}
Второй пример демонстрирует Given-When-Then с асинхронным кодом. Здесь Given задаёт состояние Firebase Cloud Messaging, When — получение push-уведомления, Then — проверку обработки.
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)
}
}
Третий пример — BDD-сценарий на Gherkin, показывающий Given-When-Then в контексте приёмочных тестов:
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, создайте несколько сценариев, где результат предыдущего становится предусловием следующего. Это делает сценарий атомарным и понятным.
Given должен описывать суть, а не конкретные цифры. Вместо «Given пользователь Иванов с балансом 500 рублей» — «Given пользователь с достаточным балансом». Конкретные данные выносятся в Scenario Outline с таблицей Examples. Это делает сценарий универсальным и переиспользуемым.
Интеграция 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 ориентирован на бизнес-язык и используется в BDD с Gherkin, а Arrange-Act-Assert — это технический формат для unit-тестов. Выбор зависит от контекста и команды.
Ограничений нет, но рекомендуется не более 3–5 проверок на один Then. Если проверок больше — сценарий, вероятно, проверяет слишком много за одно действие. Разделите его на несколько сценариев с разными Then.
Нет. Шаблон можно использовать в любом тестовом фреймворке, просто разделяя тест комментариями или пустыми строками на три блока. Gherkin нужен только если сценарии пишутся в формате .feature файлов для Cucumber или SpecFlow.
Рекомендуется выносить повторяющиеся предусловия в Background (Gherkin) или @Before-методы (JUnit). Если предусловия сложны, используйте паттерн Builder для создания тестовых данных. Это сохраняет Given коротким и читаемым.
Нет. When — это обязательный блок, описывающий действие. Если сценарий проверяет только состояние без действия (например, «при загрузке приложения данные должны быть кэшированы»), When описывает триггер: «когда приложение запускается».
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также