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 запозичив ідею тричастинної структури з формулювання тестів у TDD та методології Test-by-Example (створеної Brian Marick). Маррік запропонував описувати вимоги через приклади (examples), які одночасно слугують тестами. Given-When-Then формалізував цю ідею, перетворивши неструктуровані приклади на повторюваний шаблон.
Шаблон Given-When-Then застосовується не лише в BDD-сценаріях на Gherkin, а й у звичайних модульних тестах на JUnit, XCTest та інших фреймворках. Коментарі в коді, що розділяють тест на три блоки, — поширена практика для покращення читабельності тестової бази. 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, бізнес-аналіз | Модульне тестування |
| Мова | Природна (Gherkin) | Код (Kotlin, Swift, Java) |
| Аудиторія | Уся команда + замовник | Розробники |
| Рівень деталізації | Високорівневий | Детальний |
| Автоматизація | Cucumber, SpecFlow | JUnit, XCTest, Mockito |
Шаблон Given-When-Then оптимальний для сценаріїв, які обговорюються із замовником або аналітиком: acceptance criteria функцій, сценарії використання, регресійні перевірки. Синтаксис Gherkin дозволяє писати такі сценарії без знання програмування.
Arrange-Act-Assert — природний вибір для модульних тестів, які перевіряють конкретний метод або клас. Формат 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 у мобільному проєкті автоматично запускає 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 — це технічний формат для модульних тестів. Вибір залежить від контексту та команди.
Обмежень немає, але рекомендується не більше 3–5 перевірок на один Then. Якщо перевірок більше — сценарій, ймовірно, перевіряє забагато за одну дію. Розділіть його на кілька сценаріїв із різними Then.
Ні. Шаблон можна використовувати в будь-якому тестовому фреймворку, просто розділяючи тест коментарями або порожніми рядками на три блоки. Gherkin потрібен лише якщо сценарії пишуться у форматі .feature файлів для Cucumber або SpecFlow.
Рекомендується виносити повторювані передумови в Background (Gherkin) або @Before-методи (JUnit). Якщо передумови складні, використовуйте патерн Builder для створення тестових даних. Це зберігає Given коротким і читабельним.
Ні. When — це обов'язковий блок, що описує дію. Якщо сценарій перевіряє лише стан без дії (наприклад, «при завантаженні додатку дані повинні бути кешовані»), When описує тригер: «коли додаток запускається».
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також