Given-When-Then — egy strukturális minta tesztforgatókönyvek leírására, amelyet a BDD a domain-driven design-ból kölcsönzött és a Behaviour-Driven Development-hez adaptált. A formátum három logikai részre osztja a forgatókönyvet: előfeltételek (Given), cselekvés (When) és várt eredmény (Then). Martin Fowler (2023) szerint a Given-When-Then nem csupán egy tesztformátum, hanem egy gondolkodási eszköz, amely fegyelmezi a követelmények elemzését és a forgatókönyvek tervezését a megvalósítás megkezdése előtt.
Főbb pontok
Given-When-Then — egy viselkedésleíró minta, amelyet először Dan North fogalmazott meg 2006-ban a Behavior-Driven Development módszertan részeként. A minta megoldja a strukturálatlan tesztforgatókönyv-leírások problémáját, amelyek gyakran az előfeltételek, cselekvések és ellenőrzések tetszőleges sorrendű keverékét tartalmazzák.
A minta fő ötlete a felelősségi körök szétválasztása a három blokk között. Minden blokk pontosan a forgatókönyv egy aspektusáért felel: az előtti állapotért, a közbeni eseményért és az utáni ellenőrzésért. Ez a forgatókönyvet olvashatóvá, ellenőrizhetővé és automatizálhatóvá teszi. A Cucumber keretrendszer fejlesztőinek kutatása (2024) szerint a Given-When-Then mintát szigorúan követő forgatókönyvek 42%-kal kevesebb időt igényelnek a csapat új tagja általi megértéshez.
Dan North a háromrészes szerkezet ötletét a TDD-ből származó formulation of tests-ből és a Test-by-Example módszertanból (Brian Marick alkotta) kölcsönözte. Marick azt javasolta, hogy a követelményeket példákon (examples) keresztül írják le, amelyek egyben tesztekként is szolgálnak. A Given-When-Then formalizálta ezt az ötletet, a strukturálatlan példákat ismételhető mintává alakítva.
A Given-When-Then mintát nemcsak BDD-forgatókönyvekben (Gherkin) alkalmazzák, hanem a szokásos egységtesztekben is, mint a JUnit, XCTest és más keretrendszerek. A kódban lévő megjegyzések, amelyek három blokkra osztják a tesztet, általános gyakorlat a tesztbázis olvashatóságának javítására. A Google ezt a megközelítést ajánlja „Software Engineering at Google” (2020) című könyvében.
Minden Given-When-Then blokk szigorúan meghatározott szemantikával és kitöltési szabályokkal rendelkezik. E szabályok megsértése olyan forgatókönyvekhez vezet, amelyeket nehéz automatizálni vagy megérteni.
A Given blokk leírja a rendszer állapotát a tesztelt cselekvés végrehajtása előtt. Tartalmazza: meglévő objektumokat (felhasználó, rendelés, beállítások), aktív állapotokat (hitelesített, hálózatra csatlakoztatott), valamint az adatok kezdeti értékeit. Minden Given-nek ellenőrizhetőnek kell lennie — ha a rendszer állapota nem felel meg a Given-nek, a forgatókönyvet ki kell hagyni, vagy a tesztkörnyezetet előre fel kell készíteni.
A When blokk leírja azt az egyetlen eseményt, amely elindítja a tesztelt viselkedést. Ez lehet metódus meghívása, gomb megnyomása, értesítés vagy szerver válasz fogadása. A kulcsszabály — egy When forgatókönyvenként. Ha cselekvések sorozatát kell ellenőrizni, külön forgatókönyveket kell létrehozni, nem When-láncot.
// Given: tesztadatok létrehozása
val user = User(email = "test@example.com", balance = 500.0)
val product = Product(price = 150.0)
// When: cselekvés végrehajtása
val result = PurchaseUseCase().buy(user, product)
// Then: eredmény ellenőrzése
assertEquals(PurchaseResult.Success, result)
assertEquals(350.0, user.balance)
A Then blokk ellenőrzi, hogy a rendszer a várt állapotba került-e. Ez magában foglalja: visszaadott értékeket, objektumok állapotváltozásait, külső szolgáltatások hívásait (mock-ellenőrzésen keresztül), valamint UI-változásokat. Minden Then blokk több ellenőrzést is tartalmazhat, de mindegyik egyetlen cselekvésre vonatkozik.
Given-When-Then és Arrange-Act-Assert (AAA) — ugyanazon háromrészes minta két változata, de eltérő célközönséggel. Különbségeik megértése segít kiválasztani a megfelelő formátumot egy adott feladathoz.
| Szempont | Given-When-Then | Arrange-Act-Assert |
|---|---|---|
| Eredet | BDD, üzleti elemzés | Egységtesztelés |
| Nyelv | Természetes (Gherkin) | Kód (Kotlin, Swift, Java) |
| Célközönség | Teljes csapat + ügyfél | Fejlesztők |
| Részletesség szintje | Magas szintű | Részletes |
| Automatizálás | Cucumber, SpecFlow | JUnit, XCTest, Mockito |
A Given-When-Then minta optimális azokhoz a forgatókönyvekhez, amelyeket az ügyféllel vagy elemzővel beszélnek meg: funkciók elfogadási kritériumai, használati forgatókönyvek, regressziós ellenőrzések. A Gherkin szintaxis lehetővé teszi ilyen forgatókönyvek írását programozási ismeretek nélkül.
Arrange-Act-Assert — a természetes választás az egységtesztekhez, amelyek egy adott metódust vagy osztályt ellenőriznek. Az AAA formátum nem igényel további keretrendszereket, és bármely programozási nyelvben működik. iOS-fejlesztéshez az Apple az AAA-t ajánlja az XCTest dokumentációjában (2024).
Nézzünk gyakorlati példákat a Given-When-Then-re Kotlinban egy Android-alkalmazáshoz. Az első példa — bevásárlókosár tesztelése MockK használatával. A második — push-értesítések logikájának tesztelése.
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)
}
}
A második példa a Given-When-Then-t mutatja be aszinkron kóddal. Itt a Given beállítja a Firebase Cloud Messaging állapotát, a When — a push-értesítés fogadását, a Then — a feldolgozás ellenőrzését.
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)
}
}
A harmadik példa — egy BDD-forgatókönyv Gherkin-ben, amely a Given-When-Then-t mutatja be az elfogadási tesztek kontextusában:
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
A Given-When-Then hatékony használata több bevált gyakorlat betartását igényli. Ezek biztosítják a forgatókönyvek olvashatóságát, karbantarthatóságát és automatizálhatóságát.
Szigorú szabály: egy forgatókönyv — egy cselekvés. Ha több When sorozatát kell ellenőrizni, hozzon létre több forgatókönyvet, ahol az előző eredménye a következő előfeltételévé válik. Ez atomivá és érthetővé teszi a forgatókönyvet.
A Given-nek a lényeget kell leírnia, nem konkrét számokat. „Given Ivanov felhasználó 500 rubel egyenleggel” helyett — „Given megfelelő egyenleggel rendelkező felhasználó”. A konkrét adatok a Scenario Outline-ba kerülnek a Examples táblával. Ez a forgatókönyvet univerzálissá és újrafelhasználhatóvá teszi.
A Given-When-Then forgatókönyvek integrálása a folyamatos integrációs pipeline-ba dokumentációból regresszió elleni védelemmé alakítja őket. Minden egyes merge request egy mobil projektben automatikusan elindítja a BDD-forgatókönyveket, és blokkolja az egyesítést, ha legalább egy forgatókönyv meghiúsul.
A BDD-forgatókönyvek Cucumber-ben Androidhoz a Gradle-feladaton ./gradlew cucumber keresztül indulnak. iOS-hez (Quick/Nimble) — xcodebuild test segítségével. CI-rendszerekben (GitHub Actions, GitLab CI, Bitrise) a BDD-tesztek emulátorokon vagy valós eszközökön futnak. A jelentés HTML-formátumban készül, amely a vezetők számára is érthető: zöld forgatókönyvek — sikeres, piros — sikertelen a lépés megjelölésével.
A .feature fájlok a kód mellett a repository-ban tárolódnak, és code review-n esnek át. Az elemző a fejlesztés megkezdése előtt új forgatókönyvekkel hoz létre merge request-et (BDD-first). A fejlesztő megírja a step definitions-t és a megvalósítást, hogy ezek a forgatókönyvek zöldre váltsanak. Amikor az összes forgatókönyv sikeres — a funkcionalitás kész. Ez a megközelítés, amelyet Gojko Adzic „Specification by Example” (2011) című könyve ír le, a követelményeket végrehajtható artefaktummá alakítja.
Gyakran ismételt kérdések
Szerkezetét tekintve — igen, ez ugyanaz a háromrészes minta. A különbség a célközönségben van: a Given-When-Then az üzleti nyelvre orientálódik, és BDD-ben használják Gherkin-nel, míg az Arrange-Act-Assert egy technikai formátum egységtesztekhez. A választás a kontextustól és a csapattól függ.
Nincs korlátozás, de ajánlott legfeljebb 3–5 ellenőrzés egy Then-enként. Ha több az ellenőrzés, a forgatókönyv valószínűleg túl sokat tesztel egyetlen cselekvéssel. OSSZA fel több forgatókönyvre különböző Then-ekkel.
Nem. A minta bármely tesztkeretrendszerben használható, egyszerűen megjegyzésekkel vagy üres sorokkal három blokkra osztva a tesztet. Gherkin csak akkor szükséges, ha a forgatókönyvek .feature fájl formátumban készülnek Cucumber vagy SpecFlow számára.
Ajánlott az ismétlődő előfeltételeket Background-ba (Gherkin) vagy @Before metódusokba (JUnit) áthelyezni. Ha az előfeltételek összetettek, használja a Builder mintát a tesztadatok létrehozásához. Ez a Given-t rövid és olvasható formában tartja.
Nem. A When egy kötelező blokk, amely a cselekvést írja le. Ha a forgatókönyv csak az állapotot ellenőrzi cselekvés nélkül (például „a alkalmazás betöltésekor az adatokat gyorsítótárazni kell”), a When leírja a triggert: „amikor az alkalmazás elindul”.
Összegzés
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is