Guides · 1 of 7
Write feature files
A feature file is the part of the suite everyone reads. Scenarios, Background, Outlines, tables, docstrings, tags, and other languages, with the Rust each one needs.
One scenario
A file starts with Feature: and holds one or more
scenarios. Each scenario is a list of steps, and each step starts
with a keyword: Given for the starting state,
When for the action, Then for the
result. And and But continue whichever
keyword came before.
Feature: Lantern delivery
Scenario: Deliver a lantern
Given a lantern on the trolley
When the departure bell rings
Then the lantern arrives upright
Compiled and run against rstest-bdd 0.6.0.
Write steps about what someone could observe, not about the code
that makes it happen. “The lantern arrives upright” survives a
rewrite of the trolley; “upright is true” does not.
Background, tables, and docstrings
A Background runs before every scenario in the file.
A data table follows a step as rows between pipes; a docstring
follows a step between triple quotes. Both belong to the step
above them.
Feature: Packing the hamper
Background:
Given an empty hamper
Scenario: Pack the picnic
When the following items are packed:
| item | quantity | fragile |
| shortbread | 12 | no |
| teapot | 1 | yes |
| lantern | 2 | yes |
Then the hamper holds 15 items
And 2 kinds of item need careful handling
Scenario: Leave a note on top
When a note is tucked under the lid:
"""
Back by dusk.
Save Marrow a biscuit.
"""
Then the note mentions "biscuit"
Compiled and run against rstest-bdd 0.6.0.
A step receives its table through a #[datatable]
parameter and its docstring through a parameter named
docstring. Rows<Item> parses each
row into a struct that derives DataTableRow, matching
columns to fields by the header; #[datatable(truthy)]
reads “yes” and “no” as booleans.
//! A `DataTableRow` struct binding a Gherkin data table, and a step that
//! captures a doc string as a plain `String` argument.
use rstest::fixture;
use rstest_bdd::datatable::Rows;
use rstest_bdd_macros::{DataTableRow, given, scenario, then, when};
#[derive(Debug, DataTableRow)]
struct Item {
item: String,
quantity: u32,
#[datatable(truthy)]
fragile: bool,
}
#[derive(Default)]
struct Hamper {
items: Vec<Item>,
note: String,
}
#[fixture]
fn hamper() -> Hamper {
Hamper::default()
}
#[given("an empty hamper")]
fn empty(hamper: &mut Hamper) {
hamper.items.clear();
}
#[when("the following items are packed:")]
fn pack(hamper: &mut Hamper, #[datatable] rows: Rows<Item>) {
hamper.items.extend(rows);
}
#[then("the hamper holds {total:u32} items")]
fn holds(hamper: &Hamper, total: u32) {
let packed: u32 = hamper.items.iter().map(|row| row.quantity).sum();
assert_eq!(packed, total);
}
#[then("{kinds:usize} kinds of item need careful handling")]
fn fragile(hamper: &Hamper, kinds: usize) {
let careful: Vec<&str> = hamper
.items
.iter()
.filter(|row| row.fragile)
.map(|row| row.item.as_str())
.collect();
assert_eq!(careful.len(), kinds, "fragile: {careful:?}");
}
#[when("a note is tucked under the lid:")]
fn tuck(hamper: &mut Hamper, docstring: String) {
hamper.note = docstring;
}
#[then("the note mentions \"{word}\"")]
fn mentions(hamper: &Hamper, word: String) {
assert!(hamper.note.contains(&word), "note: {:?}", hamper.note);
}
#[scenario(path = "tests/features/hamper.feature", name = "Pack the picnic")]
fn pack_the_picnic(hamper: Hamper) {
let _ = hamper;
}
#[scenario(path = "tests/features/hamper.feature", name = "Leave a note on top")]
fn leave_a_note(hamper: Hamper) {
let _ = hamper;
}
Compiled and run against rstest-bdd 0.6.0.
Scenario Outlines
An Outline is a scenario with placeholders in angle brackets and
an Examples table. Each row becomes a test case, and
each <placeholder> is replaced by that row’s
value before any step is matched, so the steps see
a trolley carrying 2 lanterns.
Feature: Counting lanterns
Scenario Outline: Deliver <count> lanterns
Given a trolley carrying <count> lanterns
When the departure bell rings
Then <count> lanterns arrive at the picnic
Examples:
| count |
| 1 |
| 2 |
| 0 |
Compiled and run against rstest-bdd 0.6.0.
The rows run as counting_lanterns::case_1,
case_2, and case_3. The Rust is on the
getting started
page.
Other languages
A # language: line at the top of the file switches
the keywords to any language Gherkin knows. Nothing else needs
configuring; the step patterns are written in the same language
as the steps.
# language: fr
Fonctionnalité: Le pique-nique aux lanternes
Scénario: Livrer une lanterne
Soit une lanterne sur le chariot
Quand la cloche du départ sonne
Alors la lanterne arrive debout
Compiled and run against rstest-bdd 0.6.0.
//! A scenario written in French, exercising the `# language: fr` Gherkin
//! header and its Soit/Quand/Alors keywords.
use rstest::fixture;
use rstest_bdd_macros::{given, scenario, then, when};
#[derive(Default)]
struct Chariot {
debout: bool,
arrive: bool,
}
#[fixture]
fn chariot() -> Chariot {
Chariot::default()
}
#[given("une lanterne sur le chariot")]
fn charger(chariot: &mut Chariot) {
chariot.debout = true;
}
#[when("la cloche du départ sonne")]
fn partir(chariot: &mut Chariot) {
chariot.arrive = true;
}
#[then("la lanterne arrive debout")]
fn verifier(chariot: &Chariot) {
assert!(chariot.arrive && chariot.debout);
}
#[scenario(path = "tests/features/pique_nique.feature")]
fn livrer_une_lanterne(chariot: Chariot) {
let _ = chariot;
}
Compiled and run against rstest-bdd 0.6.0.
The repository’s japanese-ledger example does the
same in Japanese, with a 背景 (Background) and
typed placeholders.