| name | bdd-testing |
| description | Implement Behaviour-Driven Development with Gherkin scenarios, step definitions, and living documentation. Outputs feature files, step definitions, scenario organisation, and CI integration. |
| argument-hint | ["language/framework","team structure","existing test coverage","stakeholder involvement"] |
| allowed-tools | Read, Write, Bash |
BDD Testing (Behaviour-Driven Development)
BDD bridges the gap between business stakeholders and technical teams by expressing tests in plain language. Gherkin scenarios are executable specifications — they serve as documentation, acceptance criteria, and automated tests simultaneously. The value is alignment, not just test automation.
Process
- Three amigos. PM, developer, and tester write scenarios together before development. This surfaces ambiguity early.
- Write Gherkin scenarios. Given-When-Then format describing behaviour from the user's perspective.
- Implement step definitions. Map each Gherkin step to code.
- Run scenarios as tests. Scenarios drive development (TDD-style) and serve as regression tests.
- Maintain living documentation. Scenarios stay current with the product.
Gherkin Feature Files
# features/checkout.feature
Feature: Order Checkout
As a customer
I want to complete my purchase
So that I receive the items I want
Background:
Given I am a logged-in customer
And my cart contains 2 items totalling $59.98
Scenario: Successful checkout with valid payment
When I proceed to checkout
And I enter valid shipping address "123 Main St, Springfield"
And I enter valid credit card ending in "4242"
Then my order should be confirmed
And I should receive a confirmation email
And my cart should be empty
Scenario: Checkout fails with declined card
When I proceed to checkout
And I enter valid shipping address "123 Main St, Springfield"
And I enter declined card ending in "0002"
Then I should see error "Your card was declined"
And my cart should remain unchanged
And no order should be created
Scenario Outline: Minimum order validation
Given my cart total is <cart_total>
When I proceed to checkout
Then I should <outcome>
Examples:
| cart_total | outcome |
| $0.00 | see error "Cart is empty" |
| $4.99 | see error "Minimum order is $5" |
| $5.00 | be able to proceed |
| $500.00 | be able to proceed |
Step Definitions (Python / pytest-bdd)
from pytest_bdd import given, when, then, parsers
import pytest
@pytest.fixture
def context():
return {}
@given("I am a logged-in customer")
def logged_in_customer(context, api_client):
token = api_client.login("test@example.com", "password")
context["auth_headers"] = {"Authorization": f"Bearer {token}"}
@given(parsers.parse("my cart contains {count:d} items totalling {total}"))
def cart_with_items(context, count, total, api_client):
context["cart_id"] = api_client.create_test_cart(
headers=context["auth_headers"],
item_count=count
)
@when("I proceed to checkout")
def proceed_to_checkout(context, api_client):
context["checkout_response"] = api_client.post(
"/api/v1/checkout/start",
headers=context["auth_headers"],
json={"cart_id": context["cart_id"]}
)
@when(parsers.parse('I enter valid credit card ending in "{last4}"'))
def enter_valid_card(context, last4, api_client):
context[] = api_client.post(
,
headers=context[],
json={: , : context[]}
)
():
context[].status_code ==
order = context[].json()
order[] ==
context[] = order[]
():
emails = email_service.get_sent_emails(to=context[])
( e[] e emails)
():
response = context.get() context.get()
response.status_code [, ]
message.strip() response.json().get(, )
Step Definitions (JavaScript / Cucumber)
const { Given, When, Then } = require('@cucumber/cucumber');
const { expect } = require('@playwright/test');
Given('I am a logged-in customer', async function() {
await this.page.goto('/login');
await this.page.fill('[data-testid=email]', 'test@example.com');
await this.page.fill('[data-testid=password]', 'password');
await this.page.click('[data-testid=login-btn]');
await expect(this.page).toHaveURL('/dashboard');
});
When('I proceed to checkout', async function() {
await this.page.click();
(.).();
});
(, () {
(..()).();
. = ..().();
});
Anti-Patterns to Avoid
| Anti-Pattern | Problem | Fix |
|---|
| BDD without three amigos | Scenarios written by developers only; miss business perspective | PM + dev + tester write scenarios together |
| UI-only BDD scenarios | Brittle, slow, expensive to maintain | Prefer API-level steps; use UI only for user-visible behaviour |
| Overly detailed steps | Given I click the blue button in the top-right corner | Behaviour, not implementation: Given I start a new order |
| One scenario per edge case | 200 scenarios covering the same flow | Scenario outlines for data variations; separate scenarios for behaviour variations |
| Scenarios not maintained | Living documentation becomes stale | Scenarios run in CI; failing scenarios block merge |
10 Rules
- Three amigos write scenarios before development — not after.
- Scenarios describe behaviour from the user's perspective — not implementation details.
- Each scenario tests one behaviour — not a full user journey.
- Scenario outlines handle data variations — separate scenarios handle different behaviours.
- Steps are reusable across scenarios — avoid duplicating step logic.
- Background sets up shared preconditions — not all the context for each scenario.
- Scenarios run in CI and block merge on failure — they are tests, not documentation.
- Step definitions are thin — they delegate to existing test infrastructure.
- Avoid UI automation for BDD where API calls are sufficient — it's faster and more stable.
- The feature file is the specification — if it's not in Gherkin, it's not specified.