Given-When-Then is a structural pattern for describing test scenarios, borrowed by BDD from domain-driven design and adapted for Behaviour-Driven Development. The format divides a scenario into three logical parts: preconditions (Given), action (When), and expected result (Then). According to Martin Fowler (2023), Given-When-Then is not just a test format but a thinking tool that disciplines requirements analysis and scenario design before implementation begins.
Key Takeaways
Given-When-Then is a behavior description pattern first formulated by Dan North in 2006 as part of the Behavior-Driven Development methodology. The pattern solves the problem of unstructured test scenario descriptions that often mix preconditions, actions, and assertions in arbitrary order.
The core idea of the pattern is separation of concerns among three blocks. Each block is responsible for exactly one aspect of the scenario: the state before, the event during, and the verification after. This makes the scenario readable, verifiable, and automatable. According to research by the Cucumber framework developers (2024), scenarios that strictly follow the Given-When-Then pattern require 42% less time for a new team member to understand.
Dan North borrowed the idea of a three-part structure from the formulation of tests in TDD and the Test-by-Example methodology (created by Brian Marick). Marick proposed describing requirements through examples that simultaneously serve as tests. Given-When-Then formalized this idea, turning unstructured examples into a repeatable pattern.
The Given-When-Then pattern is used not only in BDD scenarios in Gherkin but also in regular unit tests using JUnit, XCTest, and other frameworks. Comments in code that separate the test into three blocks are a common practice for improving test base readability. Google recommends this approach in its book “Software Engineering at Google” (2020).
Each Given-When-Then block has a strictly defined semantics and filling rules. Violating these rules leads to scenarios that are difficult to automate or understand.
The Given block describes the system state before executing the tested action. It includes: existing objects (user, order, settings), active states (authorized, connected to the network), and initial data values. Each Given must be verifiable — if the system state does not match the Given, the scenario should be skipped or the test environment should be pre-configured.
The When block describes a single event that initiates the behavior under test. This can be a method call, a button click, receiving a notification, or a server response. The key rule is one When per scenario. If you need to verify a sequence of actions, create separate scenarios rather than a chain of Whens.
// Given: create test data
val user = User(email = "test@example.com", balance = 500.0)
val product = Product(price = 150.0)
// When: perform the action
val result = PurchaseUseCase().buy(user, product)
// Then: verify the result
assertEquals(PurchaseResult.Success, result)
assertEquals(350.0, user.balance)
The Then block verifies that the system has transitioned to the expected state. This includes: return values, changes in object states, calls to external services (via mock verification), and UI changes. Each Then block can contain multiple assertions, but all of them relate to a single action.
Given-When-Then and Arrange-Act-Assert (AAA) are two variants of the same three-part pattern, but with different target audiences. Understanding their differences helps choose the right format for a specific task.
| Aspect | Given-When-Then | Arrange-Act-Assert |
|---|---|---|
| Origin | BDD, business analysis | Unit testing |
| Language | Natural (Gherkin) | Code (Kotlin, Swift, Java) |
| Audience | Entire team + stakeholders | Developers |
| Level of Detail | High-level | Detailed |
| Automation | Cucumber, SpecFlow | JUnit, XCTest, Mockito |
The Given-When-Then pattern is optimal for scenarios discussed with clients or analysts: feature acceptance criteria, use cases, regression checks. Gherkin syntax allows writing such scenarios without programming knowledge.
Arrange-Act-Assert is the natural choice for unit tests that verify a specific method or class. The AAA format requires no additional frameworks and works in any programming language. For iOS development, Apple recommends AAA in the XCTest documentation (2024).
Let’s look at practical Given-When-Then examples in Kotlin for an Android application. The first example tests a shopping cart using MockK. The second tests push notification logic.
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)
}
}
The second example demonstrates Given-When-Then with asynchronous code. Here Given sets the Firebase Cloud Messaging state, When receives a push notification, and Then verifies the processing.
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)
}
}
The third example is a BDD scenario in Gherkin, showing Given-When-Then in the context of acceptance tests:
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
Effective application of Given-When-Then requires following several proven practices. They ensure readability, maintainability, and automability of scenarios.
Strict rule: one scenario — one action. If you need to verify a sequence of multiple Whens, create several scenarios where the result of the previous one becomes the precondition of the next. This makes the scenario atomic and clear.
Given should describe the essence, not specific numbers. Instead of “Given user Ivanov with a balance of 500 rubles” — “Given a user with sufficient balance.” Specific data is moved to a Scenario Outline with an Examples table. This makes the scenario universal and reusable.
Integrating Given-When-Then scenarios into the continuous integration pipeline turns them from documentation into regression protection. Each merge request in a mobile project automatically runs BDD scenarios and blocks merging if at least one scenario fails.
BDD scenarios on Cucumber for Android are run via a Gradle task ./gradlew cucumber. For iOS (Quick/Nimble) — via xcodebuild test. In CI systems (GitHub Actions, GitLab CI, Bitrise), BDD tests run on emulators or real devices. The report is generated in HTML format understandable to managers: green scenarios — passed, red ones — failed with the failing step indicated.
.feature files are stored in the repository alongside the code and go through code review. An analyst creates a merge request with new scenarios before development starts (BDD-first). The developer writes step definitions and implementation to make these scenarios pass. When all scenarios pass — the functionality is ready. This approach, described in Gojko Adzic’s book “Specification by Example” (2011), turns requirements into an executable artifact.
Frequently Asked Questions
In terms of structure — yes, it is the same three-part pattern. The difference is in the audience: Given-When-Then is oriented toward business language and used in BDD with Gherkin, while Arrange-Act-Assert is a technical format for unit tests. The choice depends on the context and the team.
There are no strict limits, but it is recommended to have no more than 3–5 assertions per Then. If there are more assertions, the scenario is probably testing too much in a single action. Split it into several scenarios with different Then blocks.
No. The pattern can be used in any test framework by simply separating the test into three blocks with comments or blank lines. Gherkin is only needed if scenarios are written in .feature file format for Cucumber or SpecFlow.
It is recommended to extract repeating preconditions into Background (Gherkin) or @Before methods (JUnit). If preconditions are complex, use the Builder pattern to create test data. This keeps Given short and readable.
No. When is a mandatory block that describes the action. If a scenario only verifies a state without an action (for example, “when the application loads, data should be cached”), When describes the trigger: “when the application starts.”
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also