Agent Skills Framework Extension
Rust QA Patterns Skill
When to Use This Skill
Use this skill when implementing rust qa patterns patterns in your codebase.
How to Use This Skill
- Review the patterns and examples below
- Apply the relevant patterns to your implementation
- Follow the best practices outlined in this skill
Production Rust testing, code review, safety audits, and quality assurance.
Core Capabilities
- Test Strategies - Unit, integration, end-to-end testing
- Property Testing - Proptest, quickcheck, generative testing
- Safety Audits - Miri, unsafe code review, memory safety
- Performance Testing - Criterion benchmarks, profiling
- Code Quality - Clippy lints, rustfmt, code review
Comprehensive Testing
// tests/integration_tests.rs
#[cfg(test)]
mod tests {
use super::*;
use sqlx::PgPool;
use testcontainers::{clients::Cli, images::postgres::Postgres, Docker};
// Integration test with real database
#[tokio::test]
async fn test_user_creation_flow() {
let docker = Cli::default();
let postgres = Postgres::default();
let node = docker.run(postgres);
let connection_string = format!(
"postgres://postgres:postgres@127.0.0.1:{}/postgres",
node.get_host_port_ipv4(5432)
);
let pool = PgPool::connect(&connection_string).await.unwrap();
sqlx::migrate!("./migrations")
.run(&pool)
.await
.unwrap();
let repo = UserRepository::new(Arc::new(pool));
// Test creation
let user = CreateUserRequest {
email: "test@example.com".to_string(),
name: "Test User".to_string(),
};
let created = repo.create(user).await.unwrap();
assert_eq!(created.email, "test@example.com");
// Test retrieval
let found = repo.find_by_email("test@example.com").await.unwrap();
assert!(found.is_some());
// Test duplicate email
let duplicate = CreateUserRequest {
email: "test@example.com".to_string(),
name: "Another User".to_string(),
};
let result = repo.create(duplicate).await;
assert!(result.is_err());
}
// Async test with tokio
#[tokio::test]
async fn test_concurrent_requests() {
use futures::future::join_all;
let service = create_test_service().await;
let tasks: Vec<_> = (0..100)
.map(|i| {
let service = service.clone();
tokio::spawn(async move {
service.process_request(i).await
})
})
.collect();
let results = join_all(tasks).await;
assert_eq!(results.len(), 100);
assert!(results.iter().all(|r| r.is_ok()));
}
}
Property-Based Testing
// tests/property_tests.rs
use proptest::prelude::*;
proptest! {
#[test]
fn test_email_validation_properties(email in "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-z]{2,}") {
// Property: All emails matching regex should validate
prop_assert!(validate_email(&email).is_ok());
}
#[test]
fn test_user_id_roundtrip(user_id in any::<u64>()) {
// Property: Encoding and decoding should be lossless
let encoded = encode_user_id(user_id);
let decoded = decode_user_id(&encoded).unwrap();
prop_assert_eq!(user_id, decoded);
}
#[test]
fn test_pagination_invariants(
total_items in 1..1000usize,
page_size in 1..100usize
) {
// Property: All items should appear exactly once across pages
let mut seen = HashSet::new();
let num_pages = (total_items + page_size - 1) / page_size;
for page in 0..num_pages {
let items = paginate(total_items, page, page_size);
for item in items {
prop_assert!(seen.insert(item), "Duplicate item found");
}
}
prop_assert_eq!(seen.len(), total_items);
}
#[test]
fn test_serialization_roundtrip(data in any::<UserData>()) {
// Property: Serialization should be lossless
let json = serde_json::to_string(&data).unwrap();
let deserialized: UserData = serde_json::from_str(&json).unwrap();
prop_assert_eq!(data, deserialized);
}
}
Safety Audit with Miri
// tests/safety_tests.rs
// Run with: cargo miri test
#[test]
fn test_no_undefined_behavior() {
// Miri detects undefined behavior
let mut data = vec![1, 2, 3, 4, 5];
// Safe access
let first = data.first().unwrap();
assert_eq!(*first, 1);
// This would be caught by Miri if unsafe:
// let ptr = data.as_ptr();
// unsafe { *ptr.add(10) } // Out of bounds!
}
#[test]
fn test_concurrent_access() {
use std::sync::Arc;
use std::thread;
let data = Arc::new(vec![1, 2, 3]);
let handles: Vec<_> = (0..10)
.map(|_| {
let data = Arc::clone(&data);
thread::spawn(move || {
let _val = data[0];
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
// Review unsafe code
#[test]
fn test_unsafe_code_correctness() {
unsafe {
// Document invariants and safety requirements
// 1. Pointer must be valid
// 2. Alignment must be correct
// 3. No data races
let data = vec![1, 2, 3];
let ptr = data.as_ptr();
// Safe: within bounds, aligned, no races
let first = *ptr;
assert_eq!(first, 1);
}
}
Benchmark with Criterion
// benches/benchmarks.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn benchmark_hashing(c: &mut Criterion) {
c.bench_function("hash_user_id", |b| {
b.iter(|| {
let user_id = black_box("user_12345");
hash_user_id(user_id)
});
});
c.bench_function("hash_user_id_fast", |b| {
b.iter(|| {
let user_id = black_box("user_12345");
hash_user_id_optimized(user_id)
});
});
}
fn benchmark_database_operations(c: &mut Criterion) {
let runtime = tokio::runtime::Runtime::new().unwrap();
c.bench_function("insert_user", |b| {
b.to_async(&runtime).iter(|| async {
let pool = setup_test_pool().await;
insert_user(&pool, black_box("test@example.com")).await
});
});
}
criterion_group!(benches, benchmark_hashing, benchmark_database_operations);
criterion_main!(benches);
Clippy Configuration
# .clippy.toml
cognitive-complexity-threshold = 30
too-many-arguments-threshold = 8
# Cargo.toml
[lints.clippy]
pedantic = "warn"
nursery = "warn"
cargo = "warn"
# Allowed lints
module_name_repetitions = "allow"
missing_errors_doc = "allow"
# Denied lints
unwrap_used = "deny"
expect_used = "deny"
panic = "deny"
CI/CD Quality Gates
# .github/workflows/quality.yml
name: Quality Checks
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: cargo test --all-features
- name: Run tests with Miri
run: |
rustup component add miri
cargo miri test
- name: Property tests
run: cargo test --release -- --include-ignored proptest
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check formatting
run: cargo fmt -- --check
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Check documentation
run: cargo doc --no-deps --all-features
benchmark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run benchmarks
run: cargo bench --no-fail-fast
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install tarpaulin
run: cargo install cargo-tarpaulin
- name: Generate coverage
run: cargo tarpaulin --out Xml
- name: Upload to codecov
uses: codecov/codecov-action@v3
Usage Examples
Integration Testing
Apply rust-qa-patterns skill to create integration tests with testcontainers
Property Testing
Apply rust-qa-patterns skill to add proptest property-based tests for core logic
Benchmarking
Apply rust-qa-patterns skill to set up Criterion benchmarks for performance-critical code
Integration Points
- rust-development-patterns - Code under test
- error-debugging-patterns - Error analysis
- cicd-automation-patterns - Automated testing
Success Output
When successful, this skill MUST output:
✅ SKILL COMPLETE: rust-qa-patterns
Completed:
- [x] Test suite implemented (unit, integration, property-based)
- [x] Safety audit completed (Miri validation)
- [x] Performance benchmarks established (Criterion)
- [x] Code quality validated (Clippy, rustfmt)
- [x] CI/CD quality gates configured and passing
Test Results:
- Unit tests: X/X passing
- Integration tests: Y/Y passing
- Property tests: Z/Z passing
- Miri validation: PASSED (no undefined behavior)
- Clippy lints: 0 warnings (or X allowed)
- Code coverage: X% (statements), Y% (branches)
- Benchmark baseline: X ns/iter (saved for regression tracking)
Outputs:
- Test files: tests/**/*.rs
- Benchmark results: target/criterion/
- Coverage report: target/tarpaulin/index.html
- CI/CD pipeline: .github/workflows/quality.yml
Completion Checklist
Before marking this skill as complete, verify:
- All unit tests pass (cargo test)
- Integration tests pass with real dependencies (testcontainers if needed)
- Property-based tests cover critical invariants (proptest/quickcheck)
- Miri validation completes without undefined behavior errors
- Clippy lints pass with configured allowed exceptions
- Code formatted with rustfmt (cargo fmt --check)
- Benchmarks established with Criterion (baseline saved)
- Code coverage meets minimum threshold (70%+)
- CI/CD pipeline configured with all quality gates
- Unsafe code documented with safety invariants
Failure Indicators
This skill has FAILED if:
- ❌ Test failures in cargo test
- ❌ Miri detects undefined behavior or memory safety issues
- ❌ Clippy warnings not addressed or properly allowed
- ❌ rustfmt detects formatting violations
- ❌ Code coverage below 70% threshold
- ❌ Property tests fail (invariants violated)
- ❌ Integration tests fail with real dependencies
- ❌ Benchmarks show performance regression without justification
- ❌ CI/CD pipeline failing on quality gates
- ❌ Unsafe code without safety documentation
When NOT to Use
Do NOT use this skill when:
- Non-Rust codebase (use language-specific QA patterns)
- Prototyping phase (comprehensive testing premature)
- Scripts with no unsafe code or complex logic (basic testing sufficient)
- FFI bindings already tested by C library (focus on binding safety)
- Performance not critical (skip benchmarking)
- Legacy Rust code without test infrastructure (use
legacy-rust-migrationfirst) - Embedded systems with special test requirements (use
embedded-testing-patterns) - WebAssembly targets requiring browser tests (use
wasm-testing-patterns)
Use alternatives:
- Python testing →
testing-strategiesskill - JavaScript testing →
testing-strategiesskill - Legacy Rust →
legacy-rust-migrationskill - Embedded →
embedded-testing-patternsskill - WASM →
wasm-testing-patternsskill
Anti-Patterns (Avoid)
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Ignoring Miri warnings | Undefined behavior may exist | Always run Miri, fix all warnings |
| Allowing unwrap() in production | Panic on None/Err | Use unwrap_used Clippy deny, handle errors properly |
| Skipping property tests | Miss edge cases | Use proptest for critical invariants |
| No unsafe code documentation | Safety invariants unclear | Document all safety requirements with // SAFETY: |
| Testing only happy path | Errors not validated | Test error cases, panics, edge conditions |
| Mocking everything | Integration issues missed | Balance unit tests with integration tests |
| No benchmark baseline | Can't detect regressions | Save criterion baselines, track trends |
| Ignoring Clippy pedantic | Miss code quality issues | Enable pedantic, address or allow with reason |
| Hard-coded test data | Brittle tests | Use test fixtures, proptest strategies |
| No async test timeout | Hanging tests in CI | Set tokio::test timeout, use tokio::time::timeout |
Principles
This skill embodies:
- #2 First Principles - Understand Rust memory safety guarantees before testing
- #3 Keep It Simple - TDD with clear AAA pattern
- #4 Separation of Concerns - Unit vs integration vs property tests
- #5 Eliminate Ambiguity - Miri removes undefined behavior ambiguity
- #8 No Assumptions - Property tests verify invariants hold for all inputs
- #9 Quality Over Speed - Comprehensive testing prevents production bugs
Full Standard: CODITECT-STANDARD-AUTOMATION.md