Testing Guide

This guide covers MockForge’s comprehensive testing strategy, including unit tests, integration tests, end-to-end tests, and testing best practices.

Testing Overview

MockForge employs a multi-layered testing approach to ensure code quality and prevent regressions:

  • Unit Tests: Individual functions and modules
  • Integration Tests: Component interactions
  • End-to-End Tests: Full system workflows
  • Performance Tests: Load and performance validation
  • Security Tests: Vulnerability and access control testing

Unit Testing

Running Unit Tests

# Run all unit tests
cargo test --lib

# Run tests for specific crate
cargo test -p mockforge-core

# Run specific test function
cargo test test_template_rendering

# Run tests matching pattern
cargo test template

# Run tests with output
cargo test -- --nocapture

Writing Unit Tests

Basic Test Structure

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_functionality() {
        // Arrange
        let input = "test input";
        let expected = "expected output";

        // Act
        let result = process_input(input);

        // Assert
        assert_eq!(result, expected);
    }

    #[test]
    fn test_error_conditions() {
        // Test error cases
        let result = process_input("");
        assert!(result.is_err());
    }
}
}

Async Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod async_tests {
    use tokio::test;

    #[tokio::test]
    async fn test_async_operation() {
        let result = async_operation().await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_concurrent_operations() {
        let (result1, result2) = tokio::join(
            async_operation(),
            another_async_operation()
        );

        assert!(result1.is_ok());
        assert!(result2.is_ok());
    }
}
}

Integration Testing

Component Integration Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod integration_tests {
    use mockforge_core::config::MockForgeConfig;
    use mockforge_http::HttpServer;

    #[tokio::test]
    async fn test_http_server_integration() {
        // Start test server
        let config = test_config();
        let server = HttpServer::new(config);
        let addr = server.local_addr();

        tokio::spawn(async move {
            server.serve().await.unwrap();
        });

        // Wait for server to start
        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;

        // Test HTTP request
        let client = reqwest::Client::new();
        let response = client
            .get(&format!("http://{}/health", addr))
            .send()
            .await
            .unwrap();

        assert_eq!(response.status(), 200);
    }
}
}

End-to-End Testing

Full System Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod e2e_tests {
    use std::process::Command;
    use std::thread;
    use std::time::Duration;

    #[test]
    fn test_full_openapi_workflow() {
        // Start MockForge server
        let mut server = Command::new("cargo")
            .args(&["run", "--bin", "mockforge-cli", "serve",
                   "--spec", "examples/openapi-demo.json",
                   "--http-port", "3000"])
            .spawn()
            .unwrap();

        // Wait for server to start
        thread::sleep(Duration::from_secs(2));

        // Test API endpoints
        test_user_endpoints();
        test_product_endpoints();

        // Stop server
        server.kill().unwrap();
    }
}
}

Performance Testing

Load Testing

# Using hey for HTTP load testing
hey -n 1000 -c 10 http://localhost:3000/users

# Using wrk for more detailed benchmarking
wrk -t 4 -c 100 -d 30s http://localhost:3000/users

Benchmarking

#![allow(unused)]
fn main() {
// In benches/benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn benchmark_template_rendering(c: &mut Criterion) {
    let engine = TemplateEngine::new();

    c.bench_function("template_render_simple", |b| {
        b.iter(|| {
            engine.render("Hello {{name}}", &Context::from_value("name", "World"))
        })
    });
}

criterion_group!(benches, benchmark_template_rendering);
criterion_main!(benches);
}

Run benchmarks:

cargo bench

Security Testing

Input Validation Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod security_tests {
    #[test]
    fn test_sql_injection_prevention() {
        let input = "'; DROP TABLE users; --";
        let result = sanitize_input(input);

        // Ensure dangerous characters are escaped
        assert!(!result.contains("DROP"));
    }

    #[test]
    fn test_template_injection() {
        let engine = TemplateEngine::new();
        let malicious = "{{#exec}}rm -rf /{{/exec}}";

        // Should not execute dangerous commands
        let result = engine.render(malicious, &Context::new());
        assert!(!result.contains("exec"));
    }
}
}

Continuous Integration

GitHub Actions Testing

# .github/workflows/test.yml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - uses: actions-rs/toolchain@v1
      with:
        toolchain: stable
        override: true

    - name: Cache dependencies
      uses: actions/cache@v2
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

    - name: Run tests
      run: cargo test --verbose

    - name: Run clippy
      run: cargo clippy -- -D warnings

    - name: Check formatting
      run: cargo fmt --check

    - name: Run security audit
      run: cargo audit

This comprehensive testing guide ensures MockForge maintains high code quality and prevents regressions across all components and integration points.