Test-Driven Development
This guide covers the Test-Driven Development (TDD) workflow used in caro development.
TDD Principles
Section titled “TDD Principles”caro follows strict TDD principles:
- Red: Write a failing test first
- Green: Write minimal code to pass the test
- Refactor: Clean up while keeping tests green
Running Tests
Section titled “Running Tests”# Run all testscargo test
# Run specific testcargo test test_name
# Run tests with outputcargo test -- --nocapture
# Run tests in watch modecargo watch -x testTest Categories
Section titled “Test Categories”Unit Tests
Section titled “Unit Tests”Located alongside source code in src/:
#[cfg(test)]mod tests { use super::*;
#[test] fn test_safety_validation() { let validator = SafetyValidator::new(); assert!(validator.is_dangerous("rm -rf /")); assert!(!validator.is_dangerous("ls -la")); }}Integration Tests
Section titled “Integration Tests”Located in tests/:
tests/├── integration/│ ├── cli_tests.rs # CLI workflow tests│ ├── backend_tests.rs # Backend integration│ └── safety_tests.rs # Safety validation└── common/ └── mod.rs # Shared test utilitiesProperty Tests
Section titled “Property Tests”Using proptest for fuzzing:
use proptest::prelude::*;
proptest! { #[test] fn test_safety_with_random_input(s in ".*") { let validator = SafetyValidator::new(); // Should not panic on any input let _ = validator.validate(&s); }}Test Coverage
Section titled “Test Coverage”Run coverage reports:
# Install tarpaulincargo install cargo-tarpaulin
# Generate coveragecargo tarpaulin --out Html
# View reportopen tarpaulin-report.htmlWriting Good Tests
Section titled “Writing Good Tests”Test Naming
Section titled “Test Naming”Use descriptive names:
#[test]fn validates_rm_rf_root_as_critical_risk() { ... }
#[test]fn allows_safe_file_listing_commands() { ... }
#[test]fn rejects_fork_bomb_patterns() { ... }Arrange-Act-Assert
Section titled “Arrange-Act-Assert”Structure tests clearly:
#[test]fn test_command_generation() { // Arrange let backend = MockBackend::new(); let prompt = "list files";
// Act let result = backend.generate(prompt);
// Assert assert!(result.is_ok()); assert!(result.unwrap().contains("ls"));}Mocking
Section titled “Mocking”Use trait objects for testability:
pub trait ModelBackend { fn generate(&self, prompt: &str) -> Result<String>;}
struct MockBackend { response: String,}
impl ModelBackend for MockBackend { fn generate(&self, _prompt: &str) -> Result<String> { Ok(self.response.clone()) }}CI Integration
Section titled “CI Integration”Tests run automatically on every PR:
- name: Run tests run: cargo test --all-features
- name: Run clippy run: cargo clippy -- -D warnings
- name: Check formatting run: cargo fmt --check