Guides · 2 of 7
Define steps
A step definition is an ordinary Rust function with a pattern on it. The pattern decides which lines it runs for and what it pulls out of them.
Patterns
#[given], #[when], and
#[then] each take the text of the step they
implement, without its keyword. A pattern matches the whole
line, not a prefix of it, and an And or
But step is matched against the keyword it
continues.
#[given("a lantern on the trolley")]
fn load(trolley: &mut Trolley) {
trolley.loaded = true;
trolley.upright = true;
}
Compiled and run against rstest-bdd 0.6.0.
Parameters that are not placeholders are fixtures, found by
name: trolley here is the trolley
fixture. Fixtures and state
covers them.
Typed placeholders
{name} in a pattern captures text into the parameter
of the same name. {name:Type} also constrains what
matches and parses it through FromStr before the
step runs, so the function receives a number rather than a
string.
#[given("a trolley carrying {count:u32} lanterns")]
fn load(trolley: &mut Trolley, count: u32) {
trolley.lanterns = count;
}
Compiled and run against rstest-bdd 0.6.0.
Quotes in the step are part of the text, so a pattern that expects them says so, and the placeholder captures what is between them:
#[given("the forecast is \"{forecast}\"")]
Compiled and run against rstest-bdd 0.6.0.
Inferred patterns and expr
A step attribute with no pattern takes it from the function’s
name, with underscores read as spaces. A pattern may also be
given as expr = "…", the form cucumber-rs uses, which
eases moving a suite across.
Feature: Ringing the bell
Scenario: Ring it three times
Given a bell on the trolley
When the bell rings 3 times
Then the rabbit hears 3 rings
Compiled and run against rstest-bdd 0.6.0.
//! A step pattern inferred from its function name, and a cucumber-rs-style
//! `expr =` pattern with a typed placeholder.
use rstest::fixture;
use rstest_bdd_macros::{given, scenario, then, when};
#[derive(Default)]
struct Bell {
rings: u32,
}
#[fixture]
fn bell() -> Bell {
Bell::default()
}
// No pattern: it is inferred from the function name, underscores as spaces.
#[given]
fn a_bell_on_the_trolley(bell: &mut Bell) {
bell.rings = 0;
}
// cucumber-rs style, accepted to ease a migration.
#[when(expr = "the bell rings {times:u32} times")]
fn ring(bell: &mut Bell, times: u32) {
bell.rings += times;
}
#[then("the rabbit hears {count:u32} rings")]
fn hears(bell: &Bell, count: u32) {
assert_eq!(bell.rings, count);
}
#[scenario(path = "tests/features/bell.feature")]
fn ring_three_times(bell: Bell) {
let _ = bell;
}
Compiled and run against rstest-bdd 0.6.0.
Steps that return
A step may return a value instead of mutating a fixture. The
value replaces the one fixture of the same type for the steps
that follow. A Result is unwrapped: Ok
is stored, and Err fails the scenario at that step.
Feature: Sharing the shortbread
Scenario: One biscuit each
Given a tin of 12 shortbread biscuits
When 3 friends take one each
Then 9 biscuits remain in the tin
Compiled and run against rstest-bdd 0.6.0.
//! Steps that return an updated fixture value, including a fallible `when`
//! step that returns `Result<Tin, String>`.
use rstest::fixture;
use rstest_bdd_macros::{given, scenario, then, when};
#[derive(Clone, Copy, Debug, Default, PartialEq)]
struct Tin(u32);
#[fixture]
fn tin() -> Tin {
Tin::default()
}
#[given("a tin of {count:u32} shortbread biscuits")]
fn filled(count: u32) -> Tin {
Tin(count)
}
#[when("{friends:u32} friends take one each")]
fn share(tin: Tin, friends: u32) -> Result<Tin, String> {
tin.0
.checked_sub(friends)
.map(Tin)
.ok_or_else(|| format!("only {} biscuits for {friends} friends", tin.0))
}
#[then("{left:u32} biscuits remain in the tin")]
fn remain(tin: Tin, left: u32) {
assert_eq!(tin, Tin(left));
}
#[scenario(path = "tests/features/shortbread.feature")]
fn sharing(tin: Tin) {
let _ = tin;
}
Compiled and run against rstest-bdd 0.6.0.
Here the Given step fills the tin, the
When step hands back a new one, and the
Then step reads the latest. Were four friends to
arrive at a tin of three, the When step would fail
with “only 3 biscuits for 4 friends”.