Behaviour Driven Development

Behaviour-driven development turns a requirement into examples of externally visible behavior. The mechanism is the Given-When-Then scenario: initial state, action, expected result. It sits between requirements engineering and testing: stakeholders can read it before code exists, and engineers can later automate the example.

Given, when, then scenarios

Feature: Feed personalization opt-out
 
  Scenario: Opted-out users never use behavioral features
    Given the user has opted out of personalization
    And user_click_history is available
    When the home feed is ranked
    Then the request is rejected as a policy violation
 
  Scenario: Opted-out users can still receive contextual ranking
    Given the user has opted out of personalization
    And only locale is available
    When the home feed is ranked
    Then the contextual ranker is used

The scenario names policy behavior, not implementation classes. That makes it suitable for documentation, review comments, and future regression tests.

Executable scenarios

This snippet runs behavior-style examples against a small shipping-fee rule and prints whether each scenario matches the expected outcome.

def route_feed(opted_out: bool, available_features: set[str]) -> str:
    if opted_out and "user_click_history" in available_features:
        return "policy_violation"
    if opted_out:
        return "contextual_ranker"
    return "personalized_ranker"
 
scenarios = [
    ("opted out blocks behavioral features", True, {"user_click_history", "locale"}, "policy_violation"),
    ("opted out allows contextual features", True, {"locale"}, "contextual_ranker"),
    ("opted in uses personalization", False, {"user_click_history"}, "personalized_ranker"),
]
for name, opted_out, features, expected in scenarios:
    actual = route_feed(opted_out, features)
    print(f"{name}: {actual == expected} -> {actual}")

Observed output:

opted out blocks behavioral features: True -> policy_violation
opted out allows contextual features: True -> contextual_ranker
opted in uses personalization: True -> personalized_ranker

BDD is strongest for deterministic edges: authorization, consent, routing, workflow state, and fallback behavior. It is weaker for exact model scores; use evaluation datasets and golden datasets for statistical behavior. During code review, a scenario is useful if the reviewer can point to the user-visible rule it protects.

Failure modes

BDD becomes theatre when scenarios are written after implementation or restate private method names. Keep the scenario count small, name the business rule, and move brittle setup into fixtures. If every scenario requires a full browser and real provider call, the examples will be too slow to guide design.

References