Given-When-Then è un modello strutturale per descrivere scenari di test, preso in prestito dal BDD dal domain-driven design e adattato per Behaviour-Driven Development. Il formato divide lo scenario in tre parti logiche: precondizioni (Given), azione (When) e risultato atteso (Then). Secondo Martin Fowler (2023), Given-When-Then non è solo un formato di test, ma uno strumento di pensiero che disciplina l'analisi dei requisiti e la progettazione degli scenari prima dell'inizio dell'implementazione.
Punti chiave
Given-When-Then è un modello di descrizione del comportamento, formulato per la prima volta da Dan North nel 2006 come parte della metodologia Behavior-Driven Development. Il modello risolve il problema delle descrizioni non strutturate degli scenari di test, che spesso contengono un misto di precondizioni, azioni e verifiche in ordine arbitrario.
L'idea principale del modello è la separazione delle responsabilità tra tre blocchi. Ogni blocco è responsabile di un solo aspetto dello scenario: stato prima, evento durante e verifica dopo. Questo rende lo scenario leggibile, verificabile e automatizzabile. Secondo uno studio degli sviluppatori del framework Cucumber (2024), gli scenari che seguono rigorosamente il modello Given-When-Then richiedono il 42% in meno di tempo per essere compresi da un nuovo membro del team.
Dan North ha preso in prestito l'idea della struttura in tre parti dalla formulazione di test in TDD e dalla metodologia Test-by-Example (creata da Brian Marick). Marick propose di descrivere i requisiti attraverso esempi (examples) che fungono contemporaneamente da test. Given-When-Then ha formalizzato questa idea, trasformando esempi non strutturati in un modello ripetibile.
Il modello Given-When-Then non si applica solo negli scenari BDD con Gherkin, ma anche nei test unitari comuni con JUnit, XCTest e altri framework. I commenti nel codice che dividono il test in tre blocchi sono una pratica comune per migliorare la leggibilità della base di test. Google raccomanda questo approccio nel suo libro «Software Engineering at Google» (2020).
Ogni blocco di Given-When-Then ha una semantica strettamente definita e regole di compilazione. La violazione di queste regole produce scenari difficili da automatizzare o comprendere.
Il blocco Given descrive lo stato del sistema prima di eseguire l'azione sotto test. Include: oggetti esistenti (utente, ordine, impostazioni), stati attivi (autenticato, connesso alla rete) e valori iniziali dei dati. Ogni Given deve essere verificabile — se lo stato del sistema non corrisponde a Given, lo scenario deve essere saltato o l'ambiente di test preparato in anticipo.
Il blocco When descrive l'unico evento che innesca il comportamento sotto test. Può essere una chiamata a un metodo, un clic su un pulsante, la ricezione di una notifica o di una risposta dal server. La regola chiave è un When per scenario. Se è necessario verificare una sequenza di azioni, creare scenari separati, non una catena di When.
// Given: creiamo i dati di test
val user = User(email = "test@example.com", balance = 500.0)
val product = Product(price = 150.0)
// When: eseguiamo l'azione
val result = PurchaseUseCase().buy(user, product)
// Then: verifichiamo il risultato
assertEquals(PurchaseResult.Success, result)
assertEquals(350.0, user.balance)
Il blocco Then verifica che il sistema sia passato allo stato atteso. Ciò include: valori restituiti, modifiche allo stato degli oggetti, chiamate a servizi esterni (tramite verifica di mock) e modifiche all'interfaccia utente. Ogni blocco Then può contenere più verifiche, ma tutte si riferiscono a una singola azione.
Given-When-Then e Arrange-Act-Assert (AAA) sono due varianti dello stesso modello in tre parti, ma con diversi pubblici di destinazione. Comprendere le loro differenze aiuta a scegliere il formato giusto per ogni attività.
| Aspetto | Given-When-Then | Arrange-Act-Assert |
|---|---|---|
| Origine | BDD, analisi di business | Test unitari |
| Linguaggio | Naturale (Gherkin) | Codice (Kotlin, Swift, Java) |
| Pubblico | Intero team + cliente | Sviluppatori |
| Livello di dettaglio | Alto livello | Dettagliato |
| Automazione | Cucumber, SpecFlow | JUnit, XCTest, Mockito |
Il modello Given-When-Then è ottimale per scenari discussi con il cliente o l'analista: criteri di accettazione delle funzionalità, casi d'uso, verifiche di regressione. La sintassi Gherkin consente di scrivere questi scenari senza conoscenze di programmazione.
Arrange-Act-Assert è la scelta naturale per i test unitari che verificano un metodo o una classe specifica. Il formato AAA non richiede framework aggiuntivi e funziona in qualsiasi linguaggio di programmazione. Per lo sviluppo iOS, Apple raccomanda AAA nella documentazione XCTest (2024).
Vediamo esempi pratici di Given-When-Then in Kotlin per un'applicazione Android. Il primo esempio è un test del carrello della spesa con MockK. Il secondo è un test della logica di notifiche 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)
}
}
Il secondo esempio dimostra Given-When-Then con codice asincrono. Qui Given imposta lo stato di Firebase Cloud Messaging, When — la ricezione di una notifica push, Then — la verifica dell'elaborazione.
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)
}
}
Il terzo esempio è uno scenario BDD in Gherkin che mostra Given-When-Then nel contesto dei test di accettazione:
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
L'applicazione efficace di Given-When-Then richiede il rispetto di diverse pratiche consolidate. Esse garantiscono leggibilità, manutenibilità e automazione degli scenari.
Regola rigorosa: uno scenario — un'azione. Se è necessario verificare una sequenza di più When, creare più scenari in cui il risultato del precedente diventa precondizione del successivo. Questo rende lo scenario atomico e comprensibile.
Given deve descrivere l'essenza, non numeri concreti. Invece di «Given l'utente Ivanov con saldo di 500 rubli» — «Given un utente con saldo sufficiente». I dati concreti vengono spostati in Scenario Outline con una tabella di Examples. Questo rende lo scenario universale e riutilizzabile.
L'integrazione degli scenari Given-When-Then nella pipeline di integrazione continua li trasforma da documentazione in protezione contro le regressioni. Ogni merge request in un progetto mobile esegue automaticamente gli scenari BDD e blocca l'unione se almeno uno scenario fallisce.
Gli scenari BDD con Cucumber per Android vengono eseguiti tramite il compito Gradle ./gradlew cucumber. Per iOS (Quick/Nimble) — tramite xcodebuild test. Nei sistemi CI (GitHub Actions, GitLab CI, Bitrise), i test BDD vengono eseguiti su emulatori o dispositivi reali. Il report viene generato in formato HTML comprensibile per i manager: scenari verdi — superati, rossi — fallimento con indicazione del passo.
I file .feature sono memorizzati nel repository accanto al codice e passano attraverso una revisione del codice. L'analista crea una merge request con nuovi scenari prima dell'inizio dello sviluppo (BDD-first). Lo sviluppatore scrive le definizioni dei passi e l'implementazione per far diventare verdi questi scenari. Quando tutti gli scenari passano — la funzionalità è pronta. Questo approccio, descritto nel libro di Gojko Adzic «Specification by Example» (2011), trasforma i requisiti in un artefatto eseguibile.
Domande frequenti
Strutturalmente sì, è lo stesso modello in tre parti. La differenza sta nel pubblico: Given-When-Then è orientato al linguaggio di business e usato in BDD con Gherkin, mentre Arrange-Act-Assert è un formato tecnico per test unitari. La scelta dipende dal contesto e dal team.
Non c'è limite, ma si raccomanda non più di 3–5 verifiche per Then. Se ci sono più verifiche, probabilmente lo scenario sta controllando troppe cose in una singola azione. Suddividetelo in più scenari con diversi Then.
No. Il modello può essere utilizzato in qualsiasi framework di test, semplicemente dividendo il test con commenti o righe vuote in tre blocchi. Gherkin è necessario solo se gli scenari sono scritti in formato .feature per Cucumber o SpecFlow.
Si raccomanda di estrarre le precondizioni ripetitive in Background (Gherkin) o metodi @Before (JUnit). Se le precondizioni sono complesse, utilizzare il pattern Builder per creare dati di test. Questo mantiene Given breve e leggibile.
No. When è un blocco obbligatorio che descrive l'azione. Se lo scenario verifica solo uno stato senza azione (ad esempio, «al caricamento dell'applicazione i dati dovrebbero essere memorizzati nella cache»), When descrive il trigger: «quando l'applicazione viene avviata».
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche