Given-When-Then — е структурен шаблон за описване на тестови сценарии, заимстван от BDD от domain-driven design и адаптиран за Behaviour-Driven Development. Форматът разделя сценария на три логически части: предварителни условия (Given), действие (When) и очакван резултат (Then). Според Мартин Фаулър (2023), Given-When-Then не е просто формат за тестове, а инструмент за мислене, който дисциплинира анализа на изискванията и проектирането на сценарии преди започване на имплементацията.
Основни точки
Given-When-Then — е шаблон за описание на поведение, формулиран за първи път от Дан Норт през 2006 г. като част от методологията Behavior-Driven Development. Шаблонът решава проблема с неструктурираните описания на тестови сценарии, които често съдържат смесица от предварителни условия, действия и проверки в произволен ред.
Основната идея на шаблона е разделяне на отговорностите между трите блока. Всеки блок отговаря за точно един аспект на сценария: състояние преди, събитие по време и проверка след. Това прави сценария четим, проверим и автоматизируем. Според проучване на разработчиците на рамката Cucumber (2024), сценариите, които стриктно следват шаблона Given-When-Then, изискват 42% по-малко време за разбиране от нов член на екипа.
Дан Норт заимства идеята за триделната структура от formulation of tests в TDD и методологията Test-by-Example (създадена от Брайън Марик). Марик предложи описването на изискванията чрез примери (examples), които едновременно служат като тестове. Given-When-Then формализира тази идея, превръщайки неструктурираните примери в повтаряем шаблон.
Шаблонът Given-When-Then се прилага не само в BDD сценарии на Gherkin, но и в обикновени unit тестове на 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, бизнес анализ | Unit тестване |
| Език | Естествен (Gherkin) | Код (Kotlin, Swift, Java) |
| Аудитория | Целият екип + клиент | Разработчици |
| Ниво на детайлност | Високо ниво | Детайлно |
| Автоматизация | Cucumber, SpecFlow | JUnit, XCTest, Mockito |
Шаблонът Given-When-Then е оптимален за сценарии, които се обсъждат с клиента или анализатора: критерии за приемане на функционалности, сценарии за използване, регресионни проверки. Синтаксисът на 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 сценарии в пайплайна за непрекъсната интеграция ги превръща от документация в защита срещу регресии. Всяка заявка за сливане в мобилен проект автоматично стартира BDD сценарии и блокира сливането при неуспех на поне един сценарий.
BDD сценариите в Cucumber за Android се стартират чрез Gradle задача ./gradlew cucumber. За iOS (Quick/Nimble) — чрез xcodebuild test. В CI системи (GitHub Actions, GitLab CI, Bitrise) BDD тестовете се изпълняват на емулатори или реални устройства. Отчетът се генерира в HTML формат, разбираем за мениджърите: зелени сценарии — преминали, червени — неуспех с посочване на стъпката.
.feature файловете се съхраняват в хранилището до кода и преминават през code review. Анализаторът създава заявка за сливане с нови сценарии преди започване на разработката (BDD-first). Разработчикът пише дефиниции на стъпките и имплементация, за да станат тези сценарии зелени. Когато всички сценарии преминат — функционалността е готова. Този подход, описан в книгата на Гойко Аджич „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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също