Guides BDD (Behavior-Driven Development) in Rust using the cucumber crate. Use when setting up cucumber tests, writing .feature files, implementing step definitions, or when the user mentions BDD, Gherkin, cucumber, behavioral testing, acceptance testing, or feature files in a Rust context.
Behavior-Driven Development in Rust using the cucumber crate (v0.22). Write Gherkin .feature files, implement step definitions in Rust, and run them as integration tests.
[dev-dependencies]
cucumber = "0.22"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
[[test]]
name = "bdd"
harness = false
harness = false tells cargo not to use the built-in test harness — cucumber provides its own. The [[test]] name must match the filename (tests/bdd.rs).
tests/
├── bdd.rs
└── features/
└── account.feature
Create tests/features/account.feature:
Feature: Bank Account
Scenario: Deposit increases balance
Given an account with a balance of 100
When I deposit 50
Then the balance should be 150
Create tests/bdd.rs:
use cucumber::{given, when, then, World};
#[derive(Debug, Default, World)]
pub struct AccountWorld {
balance: i64,
}
#[given(expr = "an account with a balance of {int}")]
fn account_with_balance(world: &mut AccountWorld, balance: i64) {
world.balance = balance;
}
#[when(expr = "I deposit {int}")]
fn deposit(world: &mut AccountWorld, amount: i64) {
world.balance += amount;
}
#[then(expr = "the balance should be {int}")]
fn balance_should_be(world: &mut AccountWorld, expected: i64) {
assert_eq!(world.balance, expected);
}
#[tokio::main]
async fn main() {
AccountWorld::run("tests/features").await;
}
cargo test --test bdd
The outside-in development loop for BDD:
Write scenario — Gherkin first, before any Rust code. Describe the behavior you want in business language.
Run and see undefined — cargo test --test bdd shows undefined steps. Cucumber prints step definition stubs you can copy.
Implement step definitions — Copy the stubs into your test file. Steps manipulate the World struct to set up state, perform actions, and assert outcomes.
Make it pass — Write the minimal production code in src/ that makes the scenario green.
Refactor — Clean up while green. Extract domain logic from steps into production modules.
Always start from a failing scenario. Never write production code without a scenario driving it. The scenario is the specification — when behavior changes, update the feature file first, then change code to match.
.fail_on_skipped() on the cucumber builder to catch undefined steps as failures instead of silent skips.@serial when they share external resources (databases, files).# Run all BDD scenarios
cargo test --test bdd
# Run scenarios matching a tag
cargo test --test bdd -- --tags @smoke
# Run with output visible (useful for debugging)
cargo test --test bdd -- --nocapture
| Concept | What it is | Where to learn more |
|---|---|---|
| Gherkin | The language for .feature files (Feature, Scenario, Given/When/Then) | references/gherkin-patterns.md |
| Steps | Rust functions annotated with #[given], #[when], #[then] | references/step-definitions.md |
| World | The struct that holds all per-scenario state | references/world-and-state.md |
| Hooks/Tags | Before/After hooks and tag-based filtering | references/hooks-and-tags.md |
| Methodology | When to use BDD, anti-patterns, outside-in workflow | references/bdd-methodology.md |
Gherkin Patterns — Feature, Scenario, Background, Scenario Outline, Data Tables, Doc Strings, Rule keyword, and writing good Gherkin.
Step Definitions — Cucumber expressions, regex patterns, async steps, module organization, and fail_on_skipped().
World and State Management — World trait, derive macro, custom constructors, state design, automatic per-scenario isolation, and nested structs.
Hooks and Tags — Before/After hooks, built-in tags (@serial, @allow.skipped), custom tags, tag inheritance, and filtering.
BDD Methodology — Outside-in development, discovery, living documentation, anti-patterns, and when BDD adds value vs. when unit tests suffice.
Basic Setup — Complete minimal project from scratch with two scenarios.
Scenario Outline — Parameterized testing with Examples tables for data-driven scenarios.
Async Steps — Async World with custom constructor and tokio-based step definitions.
Module Organization — Splitting step definitions by domain into separate files for larger projects.