rtk-tdd
rtk-ai/rtk
Enforces Red-Green-Refactor TDD discipline for Rust with idiomatic test patterns and automated workflow.
What is rtk-tdd?
This skill enforces Test-Driven Development (TDD) for Rust projects by requiring failing tests before implementation, then minimum code to pass, then refactoring. It provides Rust-idiomatic testing patterns using anyhow/thiserror, cfg(test) modules, and Arrange-Act-Assert structure, with automatic triggers on implementation, testing, refactoring, and bug-fix tasks.
- Enforces the three laws of TDD: no production code without failing test, minimal test code to fail, minimal implementation to pass
- Provides Rust-idiomatic test patterns including Arrange-Act-Assert, assert_eq!/assert!, error path testing with is_err(), and Result<()> return types
- Guides test naming conventions (test_{function}_{scenario}) and patterns for pure functions, parsing, validation, error handling, and struct roundtrips
- Runs Red-Green-Refactor cycle with cargo test verification at each stage
- Applies pre-commit gates: cargo fmt, cargo clippy, and cargo test all must pass
- Identifies when NOT to use pure TDD (Command execution, process::exit, direct I/O) and suggests refactoring strategies
How to install rtk-tdd
npx skills add null --skill rtk-tddHow to use rtk-tdd
- 1.Write a test in #[cfg(test)] mod tests within the same file using Arrange-Act-Assert structure
- 2.Run cargo test MODULE::tests::test_name and verify it fails (RED phase)
- 3.Implement the minimum code in the function to make the test pass (GREEN phase)
- 4.Run cargo test again to confirm it passes
- 5.Refactor if needed while keeping tests green
- 6.Run cargo fmt && cargo clippy --all-targets && cargo test as final gate before commit
Use cases
- Writing new Rust functions with guaranteed test coverage before implementation
- Fixing bugs by writing a failing test that reproduces the issue, then implementing the fix
- Refactoring existing code while maintaining test-driven discipline and preventing regressions
- Validating error handling paths with is_err() assertions on invalid inputs
- Testing file I/O and filesystem operations using tempfile::NamedTempFile in isolated test modules
- Rust developers practicing or learning Test-Driven Development
- Teams enforcing code quality standards with mandatory test coverage
- Backend engineers building libraries or services requiring high reliability
- Developers refactoring legacy Rust code with test-first discipline
rtk-tdd FAQ
This means your test is not actually testing anything. Rewrite it to be more specific or add assertions that will fail until the feature is implemented. Never skip the RED phase.
Refactor to return Result instead of calling exit directly, then test the Result. For Command execution, test the parser/logic separately rather than the actual command invocation.
Only with documented justification. The pre-commit gate requires cargo clippy to pass with no exceptions unless explicitly justified in comments.
Use raw string input, apply the filter/parser, then assert the output contains or does not contain expected values. For validation, test boundary inputs and assert boolean results.
Use tempfile::NamedTempFile to create isolated temporary files in tests, avoiding side effects on the real filesystem.
Full instructions (SKILL.md)
Source of truth, from rtk-ai/rtk.
name: rtk-tdd description: > Enforces TDD (Red-Green-Refactor) for Rust development. Auto-triggers on implementation, testing, refactoring, and bug fixing tasks. Provides Rust-idiomatic testing patterns with anyhow/thiserror, cfg(test), and Arrange-Act-Assert workflow. allowed-tools:
- Read
- Write
- Edit
- Bash effort: medium tags: [tdd, testing, rust, red-green-refactor, rtk]
Rust TDD Workflow
Three Laws of TDD
- Do NOT write production code without a failing test
- Write only enough test to fail (including compilation failure)
- Write only enough production code to pass the failing test
Cycle: RED (test fails) -> GREEN (minimum to pass) -> REFACTOR (cleanup, cargo test)
Red-Green-Refactor Steps
1. Write test in #[cfg(test)] mod tests of the SAME file
2. cargo test MODULE::tests::test_name -- must FAIL (red)
3. Implement the minimum in the function
4. cargo test MODULE::tests::test_name -- must PASS (green)
5. Refactor if needed, re-run cargo test (still green)
6. cargo fmt && cargo clippy --all-targets && cargo test (final gate)
Never skip step 2. If the test passes immediately, it tests nothing.
Idiomatic Rust Test Patterns
| Pattern | Usage | When |
|---|---|---|
| Arrange-Act-Assert | Base structure for every test | Always |
assert_eq! / assert! | Direct comparison / booleans | Deterministic values |
assert!(result.is_err()) | Error path testing | Invalid inputs |
Result<()> return type | Tests with ? operator | Fallible functions |
#[should_panic] | Expected panic | Invariants, preconditions |
tempfile::NamedTempFile | File/I/O tests | Filesystem-dependent code |
Patterns by Code Type
| Code Type | Test Pattern | Example |
|---|---|---|
| Pure function (str -> str) | Input literal -> assert output | assert_eq!(truncate("hello", 3), "...") |
| Parsing/filtering | Raw string -> filter -> contains/not-contains | assert!(filter(raw).contains("expected")) |
| Validation/security | Boundary inputs -> assert bool | assert!(!is_valid("../etc/passwd")) |
| Error handling | Bad input -> is_err() | assert!(parse("garbage").is_err()) |
| Struct/enum roundtrip | Construct -> serialize -> deserialize -> eq | assert_eq!(from_str(to_str(x)), x) |
Naming Convention
test_{function}_{scenario}
test_{function}_{input_type}
Examples: test_truncate_edge_case, test_parse_invalid_input, test_filter_empty_string
When NOT to Use Pure TDD
- Functions calling
Command::new()-> test the parser, not the execution std::process::exit()-> refactor toResultfirst, then test the Result- Direct I/O (SQLite, network) -> use tempfile/mock or test the pure logic separately
- Main/CLI wiring -> covered by integration/smoke tests
Pre-Commit Gate
cargo fmt --all --check
cargo clippy --all-targets
cargo test
All 3 must pass. No exceptions. No #[allow(...)] without documented justification.
Related skills
More from rtk-ai/rtk and the wider catalog.
code-simplifier
Simplify Rust code in RTK by applying idiomatic patterns without changing behavior.
design-patterns
Rust design patterns for RTK CLI filter modules: Newtype, Builder, RAII, Trait Objects, State Machine.

create-branch
Create and checkout git branches with smart validation and GitHub issue integration

asc-id-resolver
Resolve App Store Connect IDs from human-friendly names for use in other asc commands.

asc-release-flow
Validate app readiness and drive App Store submission with asc, handling metadata, builds, IAP, subscriptions, and privacy checks.

asc-submission-health
Validate App Store submission readiness, submit versions, and monitor review status with asc commands.