Skip to content
End To End Tester

Behaviour-Driven Development

BDD as a conversation practice rather than a tool choice — what the three amigos session produces, when Cucumber earns its place, and how it fails.

3 min read · updated 19 September 2026

BDD is a practice for deciding what to build, in a conversation, before anybody writes code. The tooling is downstream of that and largely optional.

This is worth stating plainly because BDD is very often adopted as "we use Cucumber now", which is roughly like adopting agile by buying Jira.

#The part that creates the value

A three amigos session: someone who knows the business need, someone who will build it, someone who will test it. Fifteen to thirty minutes. The output is a small set of concrete examples of the behaviour, including the edge cases, in language all three can argue about.

PO: Customers with an active subscription get free shipping. Tester: What about a subscription that lapsed yesterday? PO: …that should not get it. Dev: And one that lapses between adding to cart and checking out? PO: Hm. Charge at checkout time. Let me check with finance.

Those two questions are the entire return on the meeting. They were going to be asked eventually — either here, for free, or in a bug report three weeks later. That is BDD's actual mechanism: it moves the discovery of ambiguity to the cheapest possible moment.

#Recording it

The examples become scenarios in given-when-then form:

gherkin
Feature: Shipping charges

  Scenario: An active subscriber gets free shipping
    Given Alice has an active subscription
    When she checks out a basket worth £30.00
    Then shipping is free

  Scenario: A lapsed subscriber pays standard shipping
    Given Alice's subscription lapsed yesterday
    When she checks out a basket worth £30.00
    Then shipping is £3.95

  Scenario: Subscription status is taken at checkout, not at basket
    Given Alice has a subscription that expires in one minute
    And she has a basket worth £30.00
    When two minutes pass and she checks out
    Then shipping is £3.95

The third scenario is the valuable one, and it exists only because someone asked in the room.

#When the executable layer is worth it

Automating those sentences costs real effort: step definitions, a runner, a reporting layer, and the discipline to keep steps reusable. It pays back under one condition —

Someone outside engineering reads the scenarios and would notice if one were wrong.

If that is true, the feature files are living documentation: a description of the system that cannot silently go stale because it is executed on every build. That is genuinely valuable and very hard to get any other way.

If it is not true, you are maintaining an English-language indirection layer over tests only developers read, and you should write plain tests with good names instead. This is the most common BDD failure and it is entirely predictable.

#Outside-in: how BDD and TDD compose

Scenario (failing)                     ← BDD: what the business wants
  └─ acceptance test drives the API
       └─ unit test (red → green)      ← TDD: how the code works
       └─ unit test (red → green)
  Scenario passes                      ← done

The scenario frames the work and stays red for hours. Inside it, TDD cycles run in minutes. When the scenario goes green the feature is done, by a definition three people agreed on in advance.

#Keeping steps sane

Step definitions are code and deserve the same care. A codebase with four hundred one-off steps is unmaintainable; one with sixty reusable, domain-level steps is pleasant.

csharp
// Reqnroll (SpecFlow's successor). Note the step is domain-level:
// it says what is true, not how the UI achieves it.
[Given(@"(.*) has an active subscription")]
public async Task GivenAnActiveSubscription(string name) =>
    _customer = await _api.CreateCustomerAsync(name, subscription: Subscription.Active);

[When(@"(?:she|he|they) check(?:s)? out a basket worth £(.*)")]
public async Task WhenCheckingOut(decimal value) =>
    _checkout = await _ui.CheckoutBasketWorth(value);

[Then(@"shipping is free")]
public void ThenShippingIsFree() =>
    _checkout.ShippingCents.Should().Be(0);

Put UI mechanics behind objects. The step says "checks out"; a page object knows which button that is. Steps full of selectors are the fastest way to make feature files unreadable and unmaintainable at once.

Do not automate every scenario. The conversation may produce twenty examples; three might be worth an end-to-end test and the other seventeen belong in unit tests. Scenarios are for shared understanding. Automation level is a separate decision — see the testing pyramid.

#The honest failure modes

Gherkin as a UI script. When I click "#submit" — covered in given-when-then. It is the single most common degradation.

Scenario count as a metric. Teams that measure scenarios end up with hundreds of near-duplicates, each a slow end-to-end test, and a pipeline nobody can keep green.

The amigos meeting quietly dropped. The tooling survives, the practice does not, and eighteen months later nobody can explain why the tests are written in English.

If you are evaluating BDD, evaluate it as a meeting. The file format is the easy part.

Common questions

Is BDD just TDD with different words?
No. TDD is a developer's design discipline operating in minutes. BDD is a collaboration practice operating in the hours before code is written, whose output is a shared understanding of what "done" means. They compose well — the scenario from BDD frames the work, TDD drives the code inside it.
Do I need Cucumber to do BDD?
No, and most teams that adopt Cucumber without the conversation get the cost and none of the benefit. The value is in the three-amigos discussion; feature files are a way to record its output in a form that is executable.
Why do BDD adoptions fail?
Almost always because feature files become a technical artefact written by developers for developers. The moment nobody outside engineering reads them, the Gherkin layer is pure indirection and the team is better off with ordinary well-named tests.

Runnable samples for this page

last test results ↗

Working tests, not fragments — they run in CI on every push to 8exgh/endtoendtester-samples.

Was this page useful?