Rtk rtk-tdd

install
source · Clone the upstream repo
git clone https://github.com/rtk-ai/rtk
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/rtk-ai/rtk "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/rtk-tdd" ~/.claude/skills/rtk-ai-rtk-rtk-tdd && rm -rf "$T"
manifest: .claude/skills/rtk-tdd/SKILL.md
source content

Rust TDD Workflow

Three Laws of TDD

  1. Do NOT write production code without a failing test
  2. Write only enough test to fail (including compilation failure)
  3. 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

PatternUsageWhen
Arrange-Act-AssertBase structure for every testAlways
assert_eq!
/
assert!
Direct comparison / booleansDeterministic values
assert!(result.is_err())
Error path testingInvalid inputs
Result<()>
return type
Tests with
?
operator
Fallible functions
#[should_panic]
Expected panicInvariants, preconditions
tempfile::NamedTempFile
File/I/O testsFilesystem-dependent code

Patterns by Code Type

Code TypeTest PatternExample
Pure function (str -> str)Input literal -> assert output
assert_eq!(truncate("hello", 3), "...")
Parsing/filteringRaw string -> filter -> contains/not-contains
assert!(filter(raw).contains("expected"))
Validation/securityBoundary inputs -> assert bool
assert!(!is_valid("../etc/passwd"))
Error handlingBad input ->
is_err()
assert!(parse("garbage").is_err())
Struct/enum roundtripConstruct -> 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 to
    Result
    first, 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.