About tdd
tdd is a development skill that guides changes through small test-first behavior increments. It is for coding work where failures, observable behavior, and controlled refactoring need to be verified at each step.
Key features
- 01Establish a failing case first
- 02Work in small reversible increments
- 03Refactor only under passing tests
- 04Test observable behavior
- 05Report changes and verification
Use cases
- 01Repair behavior with a failing test
- 02Characterize legacy code before changes
- 03Refactor while preserving green tests
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ robsonrung/ rar-skills --skill tddAfter installing, type/tddin Claude Code to confirm it loaded.
Details
From the project READMETDD — Test-First Execution
Choose the branch before selecting a model. Coordinator work and deterministic commands proceed within invocation authority. Apply this method in the current role. It does not dispatch a worker. For a worker dispatch, use shared/references/model-preview.md and its one approved route snapshot. Nested skills and runners consume it without another selection or worker.
The Iron Law
Establish a failing behavioral case before a requested behavior repair. Reuse a captured failure when it proves the same defect on the same code.
- Preserve existing valid work. Do not delete and recreate code solely to change the order of its history.
- A passing new test can characterize existing behavior. It does not demonstrate a missing behavior or prove that the test is wrong. Use a relevant failure or controlled counterexample to establish what it detects.
Step 0 — whose code is this?
For a risky change to untested legacy code, apply safe-incremental-coding for the missing characterization. Reuse existing behavioral and failure evidence that covers the changed surface. Proceed directly when that protection already exists.
The loop
Run one loop per increment of behavior. Keep each pass small enough that you could throw it away without grief.
- Frame the smallest reversible move. One caller-visible increment of behavior — the cheapest reversible learning step, smaller than feels natural. If you can't state the outcome in a sentence, the step is too big; split it. Say it while choosing: "the smallest reversible move here is…".
- Write the test first, predict the failure, see it fail. Express what the code should do from its caller's perspective. Say the expected failure out loud before running — a different failure already taught you something.
- Get to green the simplest way. The least code that passes; naive is fine. This is a tactical step, not a design step — don't polish yet.
- Refactor under green. Improve a concrete design problem, then run the affected tests before the next behavior change. Apply
clean-codeto name a smell when one exists. Assert internal invariants where they must hold: an assertion is executable documentation, and its failure is a bug rather than a condition to catch and ignore. - Integrate coherent increments. Keep each increment small and passing. Commit only when the user or caller has authorized it; use completed behavior and passing checks to choose the boundary, not a timer.
Control the variables
You can only learn from a step if you can attribute its effect:
- One change at a time. Never bundle a refactor with a behavior change with a config tweak.
- An intermittent test is a failure, never a pass to be re-run.
- Avoid programming by coincidence. If the code passes, know why.
- Never game the check. Deleting, skipping, weakening, narrowing, or mocking-away a test to reach green is forbidden; correct a proven test implementation error within repair authority. A change to the accepted product contract needs a decision (
shared/references/engineering-rules.md, Contract integrity).
The test-writing bar
Write-time rules. test-lens is the judge when an existing test's value is in question; these are the standards you write to so it never has to convict you.
- Style ranking: output-based (assert a pure function's return) > state-based > communication-based (mocks). Push code toward output-based with a functional core (pure decisions) wrapped in a mutable shell (thin I/O glue).
- Assert observable behavior, never implementation details. Never assert calls to a stub.
- AAA — Arrange / Act / Assert, one of each — named as a domain statement of behavior:
delivery_with_a_past_date_is_invalid, nottestIsValid_case3. - A test that's hard to write is a design smell — fix the design, not the test.
- Refactoring litmus: if the implementation were swapped for a completely different one, would this test still be valid? It should be.
Design and risk cues
Use these cues while choosing tests and refactoring; they do not require another review pass before each integration.
- Farley's five levers: modularity, cohesion, separation of concerns, abstraction, low coupling. Address a regression in these properties within the changed scope.
- "What happens if…?": select the failure cases exposed by this behavior, such as invalid input, dependency failure, concurrency, security, or money loss. Reuse cases and decisions already present in the acceptance contract.
Per-step output contract
After each loop iteration (or coherent batch), report:
changed: what was edited.behavior: what the code now does that it didn't before, or that behavior was preserved.risk_guarded: the main design or data risk this step's test now guards.verification: tests or checks run, or why they could not run.
Routing
- Stored state, queues, retries, migrations, external APIs → reuse the approved data-systems-coding-lens findings. Run the lens only for an uncovered data risk or a changed design surface, not before every loop iteration.
- Apply
clean-codefor smell vocabulary and naming during the refactor step. - Apply
test-lenswhen judging whether an existing test is worth keeping. - Apply
diagnosewhen an unexplained failure surfaces mid-loop. An understood red or regression stays in the current loop; use the existing evidence instead of starting a second investigation.
Gotchas
- Monster steps — a half-day of code before the first test run.
- Test-after — a test fitted to existing code can miss the intended behavior. Check it against the acceptance contract and a relevant counterexample; preserve valid work.
- Coverage-chasing — coverage is a side effect of the loop, never the target.
- Gold-plating in green — designing while unsafe; design belongs in the refactor step.
- "No time to test" — there is no speed-vs-quality trade-off; the way to go faster is to keep rework low.
- Do not expand scope to clean unrelated code.
- Do not add layers, services, or helpers because they sound tidy.
- Do not weaken harmless local coupling when the cure adds more indirection than clarity.
- When the design needs to turn, steer green-to-green in small refactoring steps — changing your mind has a cost; that bill is the speed small steps bought you earlier.
- Do not quote or reconstruct source text from the books this skill distills.