Configures and runs rstest - Rust parametrized + fixture-based testing crate; `#[rstest]` attribute + `#[case(...)]` for parametrize; `#[fixture]` for reusable test setup; matrix tests via multiple `#[case]` × N (cartesian product); async test support via `#[async_std::test]` / `#[tokio::test]` + `#[rstest]`; `#[future]` for async fixtures. Use when working with Rust and needing parametrize/fixture patterns beyond stdlib `#[test]`.
How this skill is triggered — by the user, by Claude, or both
Slash command
/qa-unit-tests-go-rust:rstest-testsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Per [github.com/la10736/rstest][rs-gh]:
Per github.com/la10736/rstest:
rstest is a Rust crate for parametrize + fixture testing - features
that Rust's stdlib #[test] lacks. Pairs with cargo-test
(rstest tests are still discovered by cargo test).
mod tests shared state).Cargo.toml:
[dev-dependencies]
rstest = "0.21"
#[case]use rstest::rstest;
#[rstest]
#[case(1, 2, 3)]
#[case(0, 0, 0)]
#[case(-1, 1, 0)]
#[case(100, 200, 300)]
fn add_cases(#[case] a: i32, #[case] b: i32, #[case] expected: i32) {
assert_eq!(add(a, b), expected);
}
Each #[case] runs as a separate test - failures don't stop
subsequent cases. Test names become add_cases::case_1,
add_cases::case_2, etc.
#[rstest]
#[case::positive(1, 2, 3)]
#[case::zero(0, 0, 0)]
#[case::negative(-1, 1, 0)]
fn add_named(#[case] a: i32, #[case] b: i32, #[case] expected: i32) {
assert_eq!(add(a, b), expected);
}
Test names: add_named::positive, add_named::zero, etc. - much
better for failure logs.
use rstest::{fixture, rstest};
#[fixture]
fn db() -> Database {
Database::new_test_instance()
}
#[fixture]
fn user(db: Database) -> User {
db.create_user("alice")
}
#[rstest]
fn test_user_id(user: User) {
assert_eq!(user.id, 1);
}
#[rstest]
fn test_user_email(user: User, db: Database) {
assert_eq!(db.find_user(user.id).email, "[email protected]");
}
Fixtures are functions with #[fixture]; tests with #[rstest]
auto-receive them via parameter name matching. Fixture chaining
works (a fixture can request other fixtures).
#[rstest]
fn test_matrix(
#[values("alice", "bob", "charlie")] name: &str,
#[values(0, 18, 65)] age: u32,
) {
let user = User::new(name, age);
assert!(user.is_valid());
}
Runs 3 × 3 = 9 tests with all combinations. Equivalent to
nested #[case] for cartesian product.
#[case] + #[values]#[rstest]
#[case::happy("alice")]
#[case::edge("a")]
fn test_with_values(
#[case] base_name: &str,
#[values(0, 1, 100)] count: u32,
) {
// happy × 3 values = 3 tests
// edge × 3 values = 3 tests
}
use rstest::rstest;
#[rstest]
#[case(1, 2, 3)]
#[case(0, 0, 0)]
#[tokio::test]
async fn async_add_cases(#[case] a: i32, #[case] b: i32, #[case] expected: i32) {
let result = add_async(a, b).await;
assert_eq!(result, expected);
}
For async fixtures, use #[future]:
use rstest::*;
#[fixture]
async fn db_async() -> Database {
Database::connect_async().await.unwrap()
}
#[rstest]
#[tokio::test]
async fn test_async(#[future] db_async: Database) {
let db = db_async.await;
assert!(db.is_connected());
}
#[fixture]
fn user(#[default("alice")] name: &str) -> User {
User::new(name)
}
#[rstest]
#[case::alice("alice")]
#[case::bob("bob")]
fn test_user(#[case] expected_name: &str, #[with(expected_name)] user: User) {
assert_eq!(user.name, expected_name);
}
#[with(...)] injects custom args into the fixture for that test.
Same as plain cargo test:
- run: cargo test --all-targets
rstest tests are discovered + run by cargo test natively - no
separate runner.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Use rstest for single-case tests | Adds dependency for no benefit | Plain #[test] for single cases |
Skip #[case::name] | Test names become case_1, case_2; debug-hostile | Always name cases (Step 3) |
| Heavy matrix (5 dims × 5 values = 3125 tests) | Combinatorial explosion | Strategic cases vs full matrix |
| Mix sync + async tests in same parametrize | Confusing | Separate #[rstest] blocks per sync/async |
#[test].go-test,
ginkgo-tests,
cargo-test - sister toolsproptest-testing - Rust property-basedtest-code-conventionsnpx claudepluginhub testland/qa --plugin qa-unit-tests-go-rustProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.