skip to content

Write a BehaviorSpec test and explain how given/when/then map to nesting, including how Kotest avoids clashing with Kotlin's `when` keyword.

level: middleimportance: should knowfreq 55%

answer

  1. given = context, when = action, then = assertion
  2. Only then blocks are real tests
  3. `when` is a Kotlin keyword → backtick it
  4. Capitalized Given/When/Then avoid backticks
  5. And() adds extra branches

basics

~10 s

BehaviorSpec groups tests as given (a context), when (an action), then (the assertion). Because when is a Kotlin keyword, you either backtick it or use the capitalized When alias.

solid answer

~40 s

`BehaviorSpec` gives you a BDD layout: `given("...")` describes the starting context, `` `when`("...") `` describes the action under test, and `then("...")` holds the actual assertion. They nest: a `given` contains `when` blocks, each containing `then` leaves — only `then` blocks are real test cases. Because `when` is a hard Kotlin keyword, the lowercase form must be backticked: `` `when`("...") { } ``. To avoid that, Kotest provides capitalized aliases `Given`/`When`/`Then` that read cleanly without backticks. `And` variants (`xthen`, `Then`/`And`) also exist for extra context lines. Bodies live in an `init { }` block or the constructor lambda. The nesting builds readable hierarchical test names in reports.

code

kotlin · 14 lines
kotlin
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe

class WithdrawTest : BehaviorSpec({
    Given("an account with balance 100") {
        var balance = 100
        When("30 is withdrawn") {
            balance -= 30
            Then("the balance is 70") {
                balance shouldBe 70
            }
        }
    }
})

go deeper

for a junior

Knows the given/when/then triad and that it reads like BDD.

for a middle

Writes a correct nested BehaviorSpec, handles the when keyword via backticks or aliases, and knows only then is a leaf.

for a senior

Explains hierarchical naming in reports and when BDD layout aids acceptance/spec-by-example tests.

for a principal

Weighs BehaviorSpec readability vs verbosity for the team and aligns it with living-documentation/BDD practices.

## BehaviorSpec structure `BehaviorSpec` implements Behavior-Driven Development (BDD). Tests are organized into three nested levels: - **given** — the precondition/context ("given a user with an empty cart"). - **when** — the action being exercised ("when an item is added"). - **then** — the observable outcome and the actual assertions ("then the cart size is 1"). Only the **then** blocks are leaf test cases that pass or fail; `given` and `when` are containers that organize and name them. ## The `when` keyword problem `when` is a reserved Kotlin keyword (used for `when` expressions). So calling the lowercase DSL function requires **backticks**: `` `when`("...") { } ``. To avoid the awkward backticks, Kotest also exposes **capitalized aliases**: `Given`, `When`, `Then` (and `And`). These are ordinary identifiers and read fluently. ```kotlin import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe class CartTest : BehaviorSpec({ given("an empty cart") { val cart = mutableListOf<String>() `when`("an item is added") { cart.add("book") then("the cart has one item") { cart.size shouldBe 1 } } } }) // Capitalized aliases avoid backticks: class CartTest2 : BehaviorSpec({ Given("an empty cart") { val cart = mutableListOf<String>() When("an item is added") { cart.add("book") Then("the cart has one item") { cart.size shouldBe 1 } } } }) ``` ## Reporting Kotest concatenates the nesting into a hierarchical, human-readable test name in output (e.g. "Given an empty cart When an item is added Then the cart has one item"), which is the payoff of BDD-style nesting. ## Notes - `And` (`And("...")`) lets you add additional context branches under given/when. - The same engine/matchers apply; BehaviorSpec is purely a layout choice.

  • Which blocks in a BehaviorSpec actually count as test cases?
    Only the then/Then blocks are leaf tests that pass or fail; given and when are organizing containers.
  • Why does the lowercase `when` need backticks but `When` doesn't?
    `when` is a reserved Kotlin keyword so it must be escaped with backticks; `When` is a normal identifier alias Kotest provides.

Given/When/Then is like a recipe: ingredients on the counter (given), the cooking step (when), and tasting the result (then).

saying these in an interview costs you the question

  • Putting assertions in given/when instead of then
  • Claiming lowercase when works without backticks
  • Not knowing capitalized aliases exist
  • Thinking given/when blocks are independently runnable tests

context