Files
everything-claude-code/rules/rust/testing.md
Affaan Mustafa 9a478ad676 feat(rules): add Rust language rules (rebased #660) (#686)
* feat(rules): add Rust coding style, hooks, and patterns rules

Add language-specific rules for Rust extending the common rule set:
- coding-style.md: rustfmt, clippy, ownership idioms, error handling,
  iterator patterns, module organization, visibility
- hooks.md: PostToolUse hooks for rustfmt, clippy, cargo check
- patterns.md: trait-based repository, newtype, enum state machines,
  builder, sealed traits, API response envelope

Rules reference existing rust-patterns skill for deep content.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

* feat(rules): add Rust testing and security rules

Add remaining Rust language-specific rules:
- testing.md: cargo test, rstest parameterized tests, mockall mocking
  with mock! macro, tokio async tests, cargo-llvm-cov coverage
- security.md: secrets via env vars, parameterized SQL with sqlx,
  parse-don't-validate input validation, unsafe code audit requirements,
  cargo-audit dependency scanning, proper HTTP error status codes

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

* fix(rules): address review feedback on Rust rules

Fixes from Copilot, Greptile, Cubic, and CodeRabbit reviews:
- Add missing imports: use std::borrow::Cow, use anyhow::Context
- Use anyhow::Result<T> consistently (patterns.md, security.md)
- Change sqlx placeholder from ? to $1 (Postgres is most common)
- Remove Cargo.lock from hooks.md paths (auto-generated file)
- Fix tokio::test to show attribute form #[tokio::test]
- Fix mockall mock! name collision, wrap in #[cfg(test)] mod tests
- Fix --test target to match file layout (api_test, not integration)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

* fix: update catalog counts in README.md and AGENTS.md

Update documented counts to match actual repository state after rebase:
- Skills: 109 → 113 (new skills merged to main)
- Commands: 57 → 58 (new command merged to main)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

---------

Co-authored-by: Chris Yau <chris@diveanddev.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
2026-03-20 01:19:42 -07:00

3.8 KiB

paths
paths
**/*.rs

Rust Testing

This file extends common/testing.md with Rust-specific content.

Test Framework

  • #[test] with #[cfg(test)] modules for unit tests
  • rstest for parameterized tests and fixtures
  • proptest for property-based testing
  • mockall for trait-based mocking
  • #[tokio::test] for async tests

Test Organization

my_crate/
├── src/
│   ├── lib.rs           # Unit tests in #[cfg(test)] modules
│   ├── auth/
│   │   └── mod.rs       # #[cfg(test)] mod tests { ... }
│   └── orders/
│       └── service.rs   # #[cfg(test)] mod tests { ... }
├── tests/               # Integration tests (each file = separate binary)
│   ├── api_test.rs
│   ├── db_test.rs
│   └── common/          # Shared test utilities
│       └── mod.rs
└── benches/             # Criterion benchmarks
    └── benchmark.rs

Unit tests go inside #[cfg(test)] modules in the same file. Integration tests go in tests/.

Unit Test Pattern

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn creates_user_with_valid_email() {
        let user = User::new("Alice", "alice@example.com").unwrap();
        assert_eq!(user.name, "Alice");
    }

    #[test]
    fn rejects_invalid_email() {
        let result = User::new("Bob", "not-an-email");
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("invalid email"));
    }
}

Parameterized Tests

use rstest::rstest;

#[rstest]
#[case("hello", 5)]
#[case("", 0)]
#[case("rust", 4)]
fn test_string_length(#[case] input: &str, #[case] expected: usize) {
    assert_eq!(input.len(), expected);
}

Async Tests

#[tokio::test]
async fn fetches_data_successfully() {
    let client = TestClient::new().await;
    let result = client.get("/data").await;
    assert!(result.is_ok());
}

Mocking with mockall

Define traits in production code; generate mocks in test modules:

// Production trait — pub so integration tests can import it
pub trait UserRepository {
    fn find_by_id(&self, id: u64) -> Option<User>;
}

#[cfg(test)]
mod tests {
    use super::*;
    use mockall::predicate::eq;

    mockall::mock! {
        pub Repo {}
        impl UserRepository for Repo {
            fn find_by_id(&self, id: u64) -> Option<User>;
        }
    }

    #[test]
    fn service_returns_user_when_found() {
        let mut mock = MockRepo::new();
        mock.expect_find_by_id()
            .with(eq(42))
            .times(1)
            .returning(|_| Some(User { id: 42, name: "Alice".into() }));

        let service = UserService::new(Box::new(mock));
        let user = service.get_user(42).unwrap();
        assert_eq!(user.name, "Alice");
    }
}

Test Naming

Use descriptive names that explain the scenario:

  • creates_user_with_valid_email()
  • rejects_order_when_insufficient_stock()
  • returns_none_when_not_found()

Coverage

  • Target 80%+ line coverage
  • Use cargo-llvm-cov for coverage reporting
  • Focus on business logic — exclude generated code and FFI bindings
cargo llvm-cov                       # Summary
cargo llvm-cov --html                # HTML report
cargo llvm-cov --fail-under-lines 80 # Fail if below threshold

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       # Specific integration test (tests/api_test.rs)
cargo test --doc                 # Doc tests only

References

See skill: rust-testing for comprehensive testing patterns including property-based testing, fixtures, and benchmarking with Criterion.