Install any skill in seconds. Free to start, no credit card required.
Get Started Free →TDD: enforce RED-GREEN-REFACTOR, tests before code.
.claude/skills/hezaohezao-test-driven-development/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 73% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 71% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 82% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 67% | 0% |
Write the test first. Watch it fail. Write minimal code to pass.
Core principle: If you didn't watch the test fail, you don't know if it tests the right thing.
Always:
Exceptions (ask the user first):
Thinking "skip TDD just this once"? Stop. That's rationalization.
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRSTWrite code before the test? Delete it. Start over.
No exceptions:
Implement fresh from tests. Period.
Write one minimal test showing what should happen.
Good test:
pythondef test_retries_failed_operations_3_times(): attempts = 0 def operation(): nonlocal attempts attempts += 1 if attempts < 3: raise Exception('fail') return 'success' result = retry_operation(operation) assert result == 'success' assert attempts == 3
Clear name, tests real behavior, one thing.
Bad test:
pythondef test_retry_works(): mock = MagicMock() mock.side_effect = [Exception(), Exception(), 'success'] result = retry_operation(mock) assert result == 'success' # What about retry count? Timing?
Vague name, tests mock not real code.
Requirements:
MANDATORY. Never skip.
bashpytest tests/test_feature.py::test_specific_behavior -v
Confirm:
Test passes immediately? You're testing existing behavior. Fix the test.
Test errors? Fix the error, re-run until it fails correctly.
Write the simplest code to pass the test. Nothing more.
Good:
pythondef add(a, b): return a + b # Nothing extra
Bad:
pythondef add(a, b): result = a + b logging.info(f"Adding {a} + {b} = {result}") # Extra! return result
Don't add features, refactor other code, or "improve" beyond the test.
Cheating is OK in GREEN:
We'll fix it in REFACTOR.
MANDATORY.
bash# Run the specific test pytest tests/test_feature.py::test_specific_behavior -v # Then run ALL tests to check for regressions pytest tests/ -q
Confirm:
Test fails? Fix the code, not the test. Other tests fail? Fix regressions now.
After green only:
Keep tests green throughout. Don't add behavior.
If tests fail during refactor: Undo immediately. Take smaller steps.
Next failing test for next behavior. One cycle at a time.
Do not write all tests first and then all implementation. That is horizontal slicing. Use vertical tracer bullets instead:
textWRONG: RED: test1, test2, test3, test4 GREEN: impl1, impl2, impl3, impl4 RIGHT: RED→GREEN: test1→impl1 RED→GREEN: test2→impl2 RED→GREEN: test3→impl3
A tracer bullet is one end-to-end behavior slice. It proves the path works, teaches you about the interface, and keeps each next test grounded.
"I'll write tests after to verify it works"
Tests written after code pass immediately. Passing immediately proves nothing:
Test-first forces you to see the test fail, proving it actually tests something.
"Deleting X hours of work is wasteful"
Sunk cost fallacy. The time is already gone. Your choice now:
| Excuse | Reality | |--------|---------| | "Too simple to test" | Simple code breaks. Test takes 30 seconds. | | "I'll test after" | Tests passing immediately prove nothing. | | "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. | | "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is debt. | | "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. | | "Need to explore first" | Fine. Throw away exploration, start with TDD. | | "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
If you catch yourself doing any of these, delete the code and restart with TDD:
All of these mean: Delete code. Start over with TDD.
Before marking work complete:
Can't check all boxes? You skipped TDD. Start over.
| Problem | Solution | |---------|----------| | Don't know how to test | Write the wished-for API. Write the assertion first. Ask the user. | | Test too complicated | Design too complicated. Simplify the interface. | | Must mock everything | Code too coupled. Use dependency injection. | | Test setup huge | Extract helpers. Still complex? Simplify the design. |
interactions, not replace the system under test
shouldn't break them
Production code → test exists and failed first
Otherwise → not TDDNo exceptions without the user's explicit permission.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 22,626 | 13,104 | -42% | 1 | 1 | 0% | 2,435 | 4,206 | +73% | 0 | 0 | — |
case-02 | fail→pass | 20,866 | 12,068 | -42% | 1 | 1 | 0% | 2,138 | 3,655 | +71% | 0 | 0 | — |
case-03 | pass→pass | 11,453 | 6,711 | -41% | 1 | 1 | 0% | 1,880 | 2,971 | +58% | 0 | 0 | — |
case-04 | fail→pass | 19,104 | 6,741 | -65% | 1 | 1 | 0% | 2,243 | 2,929 | +31% | 0 | 0 | — |
case-05 | pass→fail | 11,757 | 6,252 | -47% | 1 | 1 | 0% | 1,851 | 2,884 | +56% | 0 | 0 | — |
case-06 | pass→pass | 24,634 | 6,968 | -72% | 1 | 1 | 0% | 1,801 | 2,905 | +61% | 0 | 0 | — |
case-07 | pass→pass | 11,168 | 5,378 | -52% | 1 | 1 | 0% | 1,465 | 2,580 | +76% | 0 | 0 | — |
case-08 | fail→pass | 10,217 | 6,159 | -40% | 1 | 1 | 0% | 1,547 | 2,811 | +82% | 0 | 0 | — |
case-09 | pass→pass | 12,155 | 8,133 | -33% | 1 | 1 | 0% | 1,889 | 2,960 | +57% | 0 | 0 | — |
case-10 | fail→pass | 11,630 | 8,643 | -26% | 1 | 1 | 0% | 1,918 | 3,199 | +67% | 0 | 0 | — |
case-11 | fail→pass | 9,700 | 7,799 | -20% | 1 | 1 | 0% | 1,634 | 2,957 | +81% | 0 | 0 | — |
case-12 | pass→pass | 11,615 | 6,707 | -42% | 1 | 1 | 0% | 1,776 | 2,732 | +54% | 0 | 0 | — |
case-13 | pass→pass | 13,908 | 10,784 | -22% | 1 | 1 | 0% | 2,055 | 3,104 | +51% | 0 | 0 | — |
case-14 | pass→pass | 9,308 | 6,952 | -25% | 1 | 1 | 0% | 1,372 | 2,861 | +109% | 0 | 0 | — |
case-15 | fail→pass | 13,578 | 9,703 | -29% | 1 | 1 | 0% | 2,153 | 3,276 | +52% | 0 | 0 | — |
case-16 | pass→pass | 11,149 | 6,814 | -39% | 1 | 1 | 0% | 1,701 | 2,834 | +67% | 0 | 0 | — |
case-17 | pass→pass | 13,313 | 10,008 | -25% | 1 | 1 | 0% | 2,075 | 3,358 | +62% | 0 | 0 | — |
case-18 | pass→pass | 9,522 | 6,275 | -34% | 1 | 1 | 0% | 1,439 | 2,621 | +82% | 0 | 0 | — |
case-19 | pass→pass | 11,724 | 7,895 | -33% | 1 | 1 | 0% | 1,946 | 3,136 | +61% | 0 | 0 | — |
case-20 | fail→pass | 11,619 | 13,769 | +19% | 1 | 1 | 0% | 2,192 | 4,024 | +84% | 0 | 0 | — |
case-21 | pass→pass | 10,562 | 5,661 | -46% | 1 | 1 | 0% | 1,422 | 2,573 | +81% | 0 | 0 | — |
case-22 | pass→pass | 15,118 | 7,101 | -53% | 1 | 1 | 0% | 2,028 | 2,593 | +28% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.