Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage. Follows TDD methodology.
source_path
skills/rust-testing/SKILL.md
origin
ECC
Rust Testing Patterns
Comprehensive Rust testing patterns for writing reliable, maintainable tests following TDD methodology.
When to Use
Writing new Rust functions, methods, or traits
Adding test coverage to existing code
Creating benchmarks for performance-critical code
Implementing property-based tests for input validation
Following TDD workflow in Rust projects
How It Works
Identify target code — Find the function, trait, or module to test
Write a test — Use #[test] in a #[cfg(test)] module, rstest for parameterized tests, or proptest for property-based tests
Mock dependencies — Use mockall to isolate the unit under test
Run tests (RED) — Verify the test fails with the expected error
Implement (GREEN) — Write minimal code to pass
Refactor — Improve while keeping tests green
Check coverage — Use cargo-llvm-cov, target 80%+
TDD Workflow for Rust
The RED-GREEN-REFACTOR Cycle
RED → Write a failing test first
GREEN → Write minimal code to pass the test
REFACTOR → Improve code while keeping tests green
REPEAT → Continue with next requirement
Step-by-Step TDD in Rust
// RED: Write test first, use todo!() as placeholderpubfnadd(a: i32, b: i32) ->i32 { todo!() }
#[cfg(test)]mod tests {
use super::*;
#[test]fntest_add() { assert_eq!(add(2, 3), 5); }
}
// cargo test → panics at 'not yet implemented'
// GREEN: Replace todo!() with minimal implementationpubfnadd(a: i32, b: i32) ->i32 { a + b }
// cargo test → PASS, then REFACTOR while keeping tests green
#[cfg(test)]mod tests {
use super::*;
/// Creates a test user with sensible defaults.fnmake_user(name: &str) -> User {
User::new(name, &format!("{name}@test.com")).unwrap()
}
#[test]fnuser_display() {
letuser = make_user("alice");
assert_eq!(user.display_name(), "alice");
}
}
# Install: cargo install cargo-llvm-cov (or use taiki-e/install-action in CI)
cargo llvm-cov # Summary
cargo llvm-cov --html # HTML report
cargo llvm-cov --lcov > lcov.info # LCOV format for CI
cargo llvm-cov --fail-under-lines 80 # Fail if below threshold
Coverage Targets
Code Type
Target
Critical business logic
100%
Public API
90%+
General code
80%+
Generated / FFI bindings
Exclude
Testing Commands
cargo test# Run all tests
cargo test -- --nocapture # Show println output
cargo test test_name # Run tests matching pattern
cargo test --lib # Unit tests only
cargo test --test api_test # Integration tests only
cargo test --doc # Doc tests only
cargo test --no-fail-fast # Don't stop on first failure
cargo test -- --ignored # Run ignored tests
Best Practices
DO:
Write tests FIRST (TDD)
Use #[cfg(test)] modules for unit tests
Test behavior, not implementation
Use descriptive test names that explain the scenario
Prefer assert_eq! over assert! for better error messages
Use ? in tests that return Result for cleaner error output
Keep tests independent — no shared mutable state
DON'T:
Use #[should_panic] when you can test Result::is_err() instead
Mock everything — prefer integration tests when feasible
Ignore flaky tests — fix or quarantine them
Use sleep() in tests — use channels, barriers, or tokio::time::pause()