suite!() { /* proc-macro */ }Expand description
A Ginkgo/RSpec-inspired BDD test suite macro.
Generates individual #[test] functions from a BDD-style DSL.
Each it block becomes a standalone test; describe/context blocks
become nested modules.
§Example
rsspec::suite! {
describe "Calculator" {
before_each {
let a = 2;
let b = 3;
}
subject { a + b }
it "adds two numbers" {
assert_eq!(subject, 5);
}
it { assert!(subject > 0); }
context "with negative numbers" {
it "handles negatives" {
assert_eq!(-1 + b, 2);
}
}
}
}§Supported DSL keywords
§Containers
describe "name" { ... }/context "name" { ... }/when "name" { ... }fdescribe/fcontext/fwhen— focused (only these run)xdescribe/xcontext/xwhen/pdescribe/pcontext/pwhen— pending (skipped)
§Specs
it "name" { ... }/specify "name" { ... }it { ... }— nameless spec (auto-namedspec_1,spec_2, etc.)fit/fspecify— focusedxit/xspecify/pit/pspecify— pending
§Lifecycle hooks
before_each { ... }— runs before everyitin this scope (and nested scopes)just_before_each { ... }— runs after allbefore_each, right before the bodyafter_each { ... }— runs after everyit(even on panic)before_all { ... }— runs once before all tests in scopeafter_all { ... }— runs once after all tests in scope
§Subject
subject { expr }— evaluated before each test body, bound aslet subject = { expr };- Nested subjects override parent (last one wins, matching RSpec semantics)
§Decorators (on it blocks)
it "name" labels("integration", "slow") { ... }— label filtering viaRSSPEC_LABEL_FILTERit "name" retries(3) { ... }— retry flaky testsit "name" must_pass_repeatedly(5) { ... }— require N consecutive passesit "name" timeout(1000) { ... }— fail if test exceeds N milliseconds
§Table-driven tests
describe_table "arithmetic" (a: i32, b: i32, expected: i32) [
"addition" (2, 3, 5),
"subtraction" (5, 3, 2),
] {
assert_eq!(a + b, expected);
}Focus/pending variants: fdescribe_table, xdescribe_table, pdescribe_table
§Ordered (sequential, fail-fast)
ordered "workflow" {
it "step 1" { create_resource(); }
it "step 2" { verify_resource(); }
}Use continue_on_failure to run all steps even if earlier ones fail:
ordered "resilient" continue_on_failure {
it "step 1" { /* ... */ }
it "step 2" { /* runs even if step 1 fails */ }
}§Execution order
before_all (once per scope) -> before_each -> just_before_each -> subject -> body -> after_each -> after_all (once per scope)