Given-When-Then — je strukturní vzor pro popis testovacích scénářů, převzatý BDD z domain-driven design a adaptovaný pro Behaviour-Driven Development. Formát rozděluje scénář do tří logických částí: předpoklady (Given), akce (When) a očekávaný výsledek (Then). Podle Martina Fowlera (2023) je Given-When-Then nejen formát testů, ale nástroj myšlení, který ukázňuje analýzu požadavků a návrh scénářů před zahájením implementace.
Hlavní body
Given-When-Then — je vzor pro popis chování, který poprvé formuloval Dan North v roce 2006 jako součást metodologie Behavior-Driven Development. Vzor řeší problém nestrukturovaných popisů testovacích scénářů, které často obsahují směs předpokladů, akcí a kontrol v libovolném pořadí.
Hlavní myšlenkou vzoru je oddělení odpovědností mezi třemi bloky. Každý blok odpovídá za přesně jeden aspekt scénáře: stav před, událost během a kontrolu po. To činí scénář čitelným, ověřitelným a automatizovatelným. Podle výzkumu vývojářů frameworku Cucumber (2024) vyžadují scénáře, které striktně dodržují vzor Given-When-Then, o 42 % méně času na pochopení novým členem týmu.
Dan North si vypůjčil myšlenku třídílné struktury z formulation of tests v TDD a metodologie Test-by-Example (vytvořené Brianem Marickem). Marick navrhl popisovat požadavky prostřednictvím příkladů (examples), které zároveň slouží jako testy. Given-When-Then tuto myšlenku formalizoval a přeměnil nestrukturované příklady na opakovatelný vzor.
Vzor Given-When-Then se aplikuje nejen v BDD scénářích v Gherkinu, ale také v běžných unit testech v JUnit, XCTest a dalších frameworkách. Komentáře v kódu rozdělující test do tří bloků jsou běžnou praxí pro zlepšení čitelnosti testovací základny. Google doporučuje tento přístup ve své knize „Software Engineering at Google” (2020).
Každý blok Given-When-Then má striktně definovanou sémantiku a pravidla plnění. Porušení těchto pravidel vede ke scénářům, které jsou obtížně automatizovatelné nebo srozumitelné.
Blok Given popisuje stav systému před provedením testované akce. Zahrnuje: existující objekty (uživatel, objednávka, nastavení), aktivní stavy (autorizován, připojen k síti) a počáteční hodnoty dat. Každý Given musí být ověřitelný — pokud stav systému neodpovídá Given, scénář by měl být přeskočen nebo testovací prostředí předem připraveno.
Blok When popisuje jedinou událost, která zahajuje testované chování. Může to být volání metody, stisknutí tlačítka, obdržení oznámení nebo odpovědi od serveru. Klíčové pravidlo — jeden When na scénář. Pokud je třeba zkontrolovat posloupnost akcí, vytvoří se samostatné scénáře, ne řetěz When.
// Given: vytváříme testovací data
val user = User(email = "test@example.com", balance = 500.0)
val product = Product(price = 150.0)
// When: provádíme akci
val result = PurchaseUseCase().buy(user, product)
// Then: kontrolujeme výsledek
assertEquals(PurchaseResult.Success, result)
assertEquals(350.0, user.balance)
Blok Then kontroluje, zda systém přešel do očekávaného stavu. To zahrnuje: návratové hodnoty, změny stavu objektů, volání externích služeb (prostřednictvím mock ověření) a změny UI. Každý blok Then může obsahovat několik kontrol, ale všechny se vztahují k jedné akci.
Given-When-Then a Arrange-Act-Assert (AAA) — jsou dvě varianty stejného třídílného vzoru, ale s odlišným cílovým publikem. Pochopení jejich rozdílů pomáhá vybrat správný formát pro konkrétní úkol.
| Aspekt | Given-When-Then | Arrange-Act-Assert |
|---|---|---|
| Původ | BDD, obchodní analýza | Unit testování |
| Jazyk | Přirozený (Gherkin) | Kód (Kotlin, Swift, Java) |
| Publikum | Celý tým + klient | Vývojáři |
| Úroveň detailu | Vysokoúrovňový | Detailní |
| Automatizace | Cucumber, SpecFlow | JUnit, XCTest, Mockito |
Vzor Given-When-Then je optimální pro scénáře, které jsou diskutovány s klientem nebo analytikem: akceptační kritéria funkcí, scénáře použití, regresní kontroly. Gherkin syntaxe umožňuje psát takové scénáře bez znalosti programování.
Arrange-Act-Assert — je přirozenou volbou pro unit testy, které kontrolují konkrétní metodu nebo třídu. Formát AAA nevyžaduje další frameworky a funguje v jakémkoli programovacím jazyce. Pro vývoj iOS Apple doporučuje AAA v dokumentaci XCTest (2024).
Podívejme se na praktické příklady Given-When-Then v Kotlinu pro Android aplikaci. První příklad — testování nákupního košíku pomocí MockK. Druhý — test logiky push oznámení.
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)
}
}
Druhý příklad demonstruje Given-When-Then s asynchronním kódem. Zde Given nastavuje stav Firebase Cloud Messaging, When — přijetí push oznámení, Then — kontrolu zpracování.
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)
}
}
Třetí příklad — BDD scénář v Gherkinu, ukazující Given-When-Then v kontextu akceptačních testů:
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
Efektivní použití Given-When-Then vyžaduje dodržování několika osvědčených postupů. Ty zajišťují čitelnost, udržovatelnost a automatizovatelnost scénářů.
Přísné pravidlo: jeden scénář — jedna akce. Pokud je třeba zkontrolovat posloupnost několika When, vytvořte několik scénářů, kde výsledek předchozího se stane předpokladem následujícího. To činí scénář atomickým a srozumitelným.
Given by měl popisovat podstatu, ne konkrétní čísla. Místo „Given uživatel Ivanov se zůstatkem 500 rublů” — „Given uživatel s dostatečným zůstatkem”. Konkrétní data se přesunou do Scenario Outline s tabulkou Examples. To činí scénář univerzálním a znovupoužitelným.
Integrace scénářů Given-When-Then do pipeline průběžné integrace je mění z dokumentace v ochranu proti regresím. Každý merge request v mobilním projektu automaticky spouští BDD scénáře a blokuje sloučení při selhání alespoň jednoho scénáře.
BDD scénáře na Cucumber pro Android se spouštějí prostřednictvím Gradle úkolu ./gradlew cucumber. Pro iOS (Quick/Nimble) — přes xcodebuild test. V CI systémech (GitHub Actions, GitLab CI, Bitrise) se BDD testy provádějí na emulátorech nebo skutečných zařízeních. Sestava je generována v HTML formátu, srozumitelném pro manažery: zelené scénáře — úspěch, červené — neúspěch s uvedením kroku.
Soubory .feature jsou uloženy v repozitáři vedle kódu a procházejí code review. Analytik vytváří merge request s novými scénáři před zahájením vývoje (BDD-first). Vývojář píše step definitions a implementaci, aby tyto scénáře zezelenaly. Když všechny scénáře procházejí — funkcionalita je hotová. Tento přístup, popsaný v knize Gojko Adzice „Specification by Example” (2011), mění požadavky na spustitelný artefakt.
Často kladené otázky
Strukturou — ano, je to stejný třídílný vzor. Rozdíl je v publiku: Given-When-Then je orientován na obchodní jazyk a používá se v BDD s Gherkinem, zatímco Arrange-Act-Assert je technický formát pro unit testy. Volba závisí na kontextu a týmu.
Neexistují omezení, ale doporučuje se ne více než 3–5 kontrol na jeden Then. Pokud je kontrol více, scénář pravděpodobně testuje příliš mnoho v jedné akci. Rozdělte ho do několika scénářů s různými Then.
Ne. Vzor lze použít v jakémkoli testovacím frameworku, jednoduše rozdělením testu komentáři nebo prázdnými řádky do tří bloků. Gherkin je potřeba pouze pokud jsou scénáře psány ve formátu .feature souborů pro Cucumber nebo SpecFlow.
Doporučuje se přesunout opakující se předpoklady do Background (Gherkin) nebo @Before metod (JUnit). Pokud jsou předpoklady složité, použijte vzor Builder pro vytváření testovacích dat. To udržuje Given krátký a čitelný.
Ne. When je povinný blok popisující akci. Pokud scénář kontroluje pouze stav bez akce (například „při načítání aplikace by data měla být uložena do mezipaměti”), When popisuje spouštěč: „když se aplikace spustí”.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také