Testing and Quality Gates
Use this recipe for unit tests, integration tests, shared test helpers, CI validation, and generated-code review criteria.
Mandatory Local Gates
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features
cargo doc --workspace --all-features --no-depsUnit Test Pattern
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validates_required_name() {
let result = CreateUserCommand::new("");
assert!(matches!(result, Err(ServiceError::InvalidInput { .. })));
}
}Async Test Pattern
#[tokio::test]
async fn saves_user() -> Result<()> {
let repository = InMemoryRepository::default();
let service = UserService::new(repository);
service.save("user-1").await?;
Ok(())
}Integration Tests
Use tests/ for public behavior that crosses crate boundaries:
tests/
health_check.rs
api_contract.rs#[test]
fn exposes_expected_version() {
assert_eq!(my_crate::VERSION, env!("CARGO_PKG_VERSION"));
}Shared Test Helpers
For workspaces, place common test helpers in a private crate:
[package]
name = "shared-tests"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
publish = falseConsume via dev-dependencies:
[dev-dependencies]
shared-tests = { path = "../shared-tests" }Test Design Rules
- Avoid sleeping in tests. Use controlled time (
tokio::time::pause/start_paused = true) when possible — this requires the tokiotest-utilfeature, so add it as a dev-dependency:tokio = { version = "1", features = ["test-util"] }under[dev-dependencies]. - Avoid tests that depend on test execution order.
- Use temporary directories/files for filesystem tests.
- Prefer real small in-memory implementations over broad mocks where feasible.
- Make error-path tests first-class, especially config, validation, timeout, and retry behavior.
- Include examples in rustdoc for public APIs.
When test suites grow large enough that cargo test wall-time matters, consider cargo-nextest (parallel, per-test-process isolation) as a drop-in runner.
CI Example
name: rust-ci
on:
pull_request:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- run: cargo fmt --all --check
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- run: cargo test --workspace --all-features
- run: cargo doc --workspace --all-features --no-depsIf a project avoids third-party GitHub Actions, replace dtolnay/rust-toolchain with rustup commands.