behave
behave is a behavior-driven testing library for Rust. It gives you a behave!
macro for nested, readable test suites and an expect! API for expressive
assertions, while still compiling down to ordinary #[test] functions.
What It Is
Use behave when you want test code that reads like scenarios instead of a flat
list of unrelated unit tests:
- nested groups instead of large test modules
setupblocks that flow into child scenarioseachblocks for parameterized/table-driven tests- built-in matchers for equality, strings, collections, options, results, and floats
pendingandfocusmarkers for test workflow- optional
cargo-behaveCLI for tree, JSON, and JUnit output plus flaky-test detection
How It Works
behave! is a proc macro. At compile time it turns your scenario tree into
standard Rust test functions, so cargo test still runs the suite and there is
no custom runtime to keep alive.
Start Fast
Add the crate as a dev-dependency:
Create tests/behave_smoke.rs:
use *;
behave!
Run it:
That is the whole onboarding path. The generated tests are normal #[test]
items, so you can keep using the usual Rust tooling around them.
Parameterized Tests
Use each to generate one test per case. Each case becomes its own #[test]
function, so failures tell you exactly which input broke:
use *;
behave!
This generates addition::case_0, addition::case_1, and addition::case_2.
Single-parameter cases work too:
use *;
behave!
each inherits setup, teardown, and tokio; from the parent group:
use *;
behave!
See examples/parameterized.rs for the full
working example.
Setup Inheritance
setup bindings flow from parent groups into child scenarios and child
setup blocks. This avoids duplicating shared state:
use *;
behave!
See examples/setup_inheritance.rs for
a fuller version with helper functions and shadowing.
Teardown
teardown blocks run after every test in the group, even if the test panics (sync tests) or returns an error (async tests). Use them for cleanup:
use *;
behave!
Inner teardowns run before outer teardowns (like destructors). See
examples/teardown.rs for nested teardown patterns.
Copy-Paste Commands
Create a new project and try behave in one go:
Then put the Quick Start example above into tests/behave_smoke.rs and run
cargo test.
Install the optional CLI:
Run the suite with tree output:
Emit a machine-readable report:
Features
| Feature | Default | Description |
|---|---|---|
std |
Yes | Standard library support |
cli |
No | Enables cargo-behave and flaky-test utilities |
color |
No | ANSI-colored diff output for assertion failures |
regex |
No | to_match_regex and to_contain_regex matchers |
tokio |
No | Enables tokio; async test generation |
Matchers
| Category | Matchers |
|---|---|
| Equality | to_equal, to_not_equal |
| Boolean | to_be_true, to_be_false |
| Ordering | to_be_greater_than, to_be_less_than, to_be_at_least, to_be_at_most |
| Option | to_be_some, to_be_none, to_be_some_with |
| Result | to_be_ok, to_be_err, to_be_ok_with, to_be_err_with |
| Collections | to_contain, to_be_empty, to_not_be_empty, to_have_length, to_contain_all_of |
| Strings | to_start_with, to_end_with, to_contain_substr, to_have_str_length |
| Float | to_approximately_equal, to_approximately_equal_within |
| Panic | expect_panic!, expect_no_panic! |
| Predicate | to_satisfy |
| Custom | to_match with BehaveMatch |
| Regex (feature) | to_match_regex, to_contain_regex |
Map (HashMap, BTreeMap) |
to_contain_key, to_contain_value, to_contain_entry, to_be_empty, to_not_be_empty, to_have_length |
| Composition | all_of, any_of, not_matching |
All matchers respect .not().
The full explanation for every matcher, including what it checks, why you would choose it, and a working example for each method, is in docs/MATCHERS.md.
Real Examples
| Example | What it shows |
|---|---|
examples/quickstart.rs |
Recommended first suite with setup, matchers, and pending |
examples/parameterized.rs |
each blocks with multi-param tuples, single params, and inherited setup |
examples/setup_inheritance.rs |
Three levels of nested setup with a realistic pricing domain |
examples/teardown.rs |
Panic-safe cleanup, nested teardowns, and resource management |
examples/custom_matcher.rs |
Reusable BehaveMatch<T> matcher type with negation |
tests/smoke.rs |
Full DSL and matcher surface coverage |
What You Can And Cannot Do
You can:
- nest groups freely
- share bindings from a parent
setupinto child scenarios - shadow a setup binding with a later
letin a childsetupor scenario body - use
eachblocks for parameterized/table-driven test generation - use
teardownblocks for cleanup after each test (panic-safe in sync, error-safe in async) - declare
tokio;in a group to generate#[tokio::test]async tests (requirestokiofeature) - use
cargo testnormally because generated tests are ordinary#[test]functions - use
cargo behavefor tree output, filters, and libtest flags - use
cargo behave --output jsonorcargo behave --output junitfor CI-friendly reports - use
cargo behave --manifest-path path/to/Cargo.tomlor--package namein workspaces
Current limitations:
- one
setupblock per group, oneteardownblock per group - DSL order within a group:
tokio;→setup {}→teardown {}→ children pendingblocks must be emptyfocusis a marker shown in generated names and CLI output; it does not automatically skip non-focused tests- async teardown is error-safe but not panic-safe (no
catch_unwindacross.awaitpoints)
Why Rely On It
The current trust signals are intentionally concrete:
behave!compiles to ordinary#[test]functions- runnable examples live in
examples/and are exercised in tests - public docs, doctests, Clippy, and rustdoc warnings are checked together
unsafeis forbidden by lint configuration- limitations are documented explicitly instead of left implicit
- security reporting is documented in SECURITY.md
For the fuller trust and maintenance picture, see docs/RELIABILITY.md.
Flaky Test Detection
Create behave.toml in your project root:
[]
= true
= ".behave/history.json"
= 5
When enabled, cargo behave records past outcomes and warns when a test fails
after many consecutive passes without source changes in the selected package set.
Add .behave/ to .gitignore.
Documentation
Security
See SECURITY.md for the reporting process.
License
Licensed under the Apache License, Version 2.0. See LICENSE.