Skip to main content
Kodelyth ECC
Command

/rust-test

Enforce TDD workflow for Rust. Write tests first, then implement. Verify 80%+ coverage with cargo-llvm-cov.

Run:/rust-test

Rust TDD Command

This command enforces test-driven development methodology for Rust code using #[test], rstest, proptest, and mockall.

What This Command Does

  • Define Types/Traits: Scaffold function signatures with todo!()
  • Write Tests: Create comprehensive test module (RED)
  • Run Tests: Verify tests fail for the right reason
  • Implement Code: Write minimal code to pass (GREEN)
  • Refactor: Improve while keeping tests green
  • Check Coverage: Ensure 80%+ coverage with cargo-llvm-cov

When to Use

Use /rust-test when:

  • Implementing new Rust functions, methods, or traits
  • Adding test coverage to existing Rust code
  • Fixing bugs (write failing test first)
  • Building critical business logic
  • Learning TDD workflow in Rust

TDD Cycle

RED     -> Write failing test first
GREEN   -> Implement minimal code to pass
REFACTOR -> Improve code, tests stay green
REPEAT  -> Next test case

Example Session

User: /rust-test I need a function to validate user registration

Agent:

TDD Session: Registration Validator

Step 1: Define Interface

rust // src/validator.rs pub struct RegistrationRequest { pub name: String, pub email: String, pub password: String, }

pub enum ValidationResult { Valid, Invalid(Vec), }

pub fn validate_registration(request: &RegistrationRequest) -> ValidationResult { todo!() }


Step 2: Write Tests (RED)

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

#[test] fn valid_registration_returns_valid() { let request = RegistrationRequest { name: "Alice".into(), email: "alice@example.com".into(), password: "SecureP@ss1".into(), }; assert!(matches!(validate_registration(&request), ValidationResult::Valid)); }

#[test] fn blank_name_returns_invalid() { let request = RegistrationRequest { name: "".into(), email: "alice@example.com".into(), password: "SecureP@ss1".into(), }; match validate_registration(&request) { ValidationResult::Invalid(errors) => { assert!(errors.contains(&"Name is required".to_string())); } ValidationResult::Valid => panic!("expected Invalid"), } }

#[test] fn invalid_email_returns_invalid() { let request = RegistrationRequest { name: "Alice".into(), email: "not-an-email".into(), password: "SecureP@ss1".into(), }; assert!(matches!( validate_registration(&request), ValidationResult::Invalid(_) )); }

#[test] fn short_password_returns_invalid() { let request = RegistrationRequest { name: "Alice".into(), email: "alice@example.com".into(), password: "short".into(), }; assert!(matches!( validate_registration(&request), ValidationResult::Invalid(_) )); } }


Step 3: Run Tests — Verify FAIL

bash $ cargo test running 4 tests test tests::valid_registration_returns_valid ... FAILED (not yet implemented) test tests::blank_name_returns_invalid ... FAILED test tests::invalid_email_returns_invalid ... FAILED test tests::short_password_returns_invalid ... FAILED

Tests fail as expected (todo! panic).

Step 4: Implement Minimal Code (GREEN)

rust pub fn validate_registration(request: &RegistrationRequest) -> ValidationResult { let mut errors = Vec::new();

if request.name.trim().is_empty() { errors.push("Name is required".into()); } if !request.email.contains('@') { errors.push("Invalid email format".into()); } if request.password.len() < 8 { errors.push("Password must be at least 8 characters".into()); }

if errors.is_empty() { ValidationResult::Valid } else { ValidationResult::Invalid(errors) } }


Step 5: Run Tests — Verify PASS

bash $ cargo test running 4 tests test tests::valid_registration_returns_valid ... ok test tests::blank_name_returns_invalid ... ok test tests::invalid_email_returns_invalid ... ok test tests::short_password_returns_invalid ... ok

test result: ok. 4 passed; 0 failed


All tests passing!

Step 6: Check Coverage

bash $ cargo llvm-cov Coverage: 100.0% of lines

Coverage: 100%

TDD Complete!

Test Patterns

Unit Tests

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

#[test] fn adds_two_numbers() { assert_eq!(add(2, 3), 5); }

#[test] fn handles_error() -> Result<(), Box<dyn std::error::Error>> { let result = parse_config(r#"port = 8080"#)?; assert_eq!(result.port, 8080); Ok(()) } }

Parameterized Tests with rstest

use rstest::{rstest, fixture};

#[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());
}

Property-Based Tests

use proptest::prelude::*;

proptest! { #[test] fn encode_decode_roundtrip(input in ".*") { let encoded = encode(&input); let decoded = decode(&encoded).unwrap(); assert_eq!(input, decoded); } }

Coverage Commands

# Summary report
cargo llvm-cov

HTML report

cargo llvm-cov --html

Fail if below threshold

cargo llvm-cov --fail-under-lines 80

Run specific test

cargo test test_name

Run with output

cargo test -- --nocapture

Run without stopping on first failure

cargo test --no-fail-fast

Coverage Targets

| Code Type | Target | |-----------|--------| | Critical business logic | 100% | | Public API | 90%+ | | General code | 80%+ | | Generated / FFI bindings | Exclude |

TDD Best Practices

DO:

  • Write test FIRST, before any implementation
  • Run tests after each change
  • Use assert_eq! over assert! for better error messages
  • Use ? in tests that return Result for cleaner output
  • Test behavior, not implementation
  • Include edge cases (empty, boundary, error paths)
DON'T:
  • Write implementation before tests
  • Skip the RED phase
  • Use #[should_panic] when Result::is_err() works
  • Use sleep() in tests — use channels or tokio::time::pause()
  • Mock everything — prefer integration tests when feasible

Related Commands

  • /rust-build - Fix build errors
  • /rust-review - Review code after implementation
  • /verify - Run full verification loop

Related

  • Skill: skills/rust-testing/
  • Skill: skills/rust-patterns/