| name | test-driven-development |
| description | Use when implementing any feature or bugfix, before writing implementation code |
Test-Driven Development (TDD)
The Iron Law
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
Write code before the test? Delete it. Start over.
No exceptions:
- Don't keep it as "reference"
- Don't "adapt" it while writing tests
- Don't look at it
- Delete means delete
Violating the letter of the rules is violating the spirit of the rules.
When to Use
Always: New features, bug fixes, refactoring, behavior changes.
Exceptions (ask your human partner): Throwaway prototypes, generated code, config files.
Red-Green-Refactor
RED — Write Failing Test
Write one minimal test showing what should happen.
Requirements:
- One behavior per test
- Clear descriptive name
- Real code (no mocks unless unavoidable)
Verify RED — Watch It Fail
MANDATORY. Never skip.
<test command> path/to/test
Confirm:
- Test fails (not errors from typos)
- Failure message is expected
- Fails because feature is missing
Test passes? You're testing existing behavior. Fix the test.
GREEN — Minimal Code
Write simplest code to pass the test.
Don't add features, refactor other code, or "improve" beyond the test.
Verify GREEN — Watch It Pass
MANDATORY.
Confirm:
- Test passes
- Other tests still pass
- Output clean (no errors, warnings)
Test fails? Fix code, not test.
REFACTOR — Clean Up
After green only:
- Remove duplication
- Improve names
- Extract helpers
Keep tests green. Don't add behavior.
Repeat
Next failing test for next behavior.
Good vs Bad Tests
| Quality | Good | Bad |
|---|
| Minimal | One thing. "and" in name? Split it. | Tests multiple behaviors |
| Clear | Name describes behavior | test('test1') |
| Real | Tests actual code | Tests mock behavior |
Common Rationalizations
| Excuse | Reality |
|---|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Need to explore first" | Fine. Throw away exploration. Start with TDD. |
| "Test hard = skip it" | Hard to test = hard to use. Fix the design. |
| "TDD will slow me down" | TDD is faster than debugging. |
| "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. |
Bug Fix Flow
- RED: Write test reproducing the bug
- Verify RED: Watch it fail with the bug
- GREEN: Fix the bug (minimal code)
- Verify GREEN: Test passes, all tests pass
- Commit
Never fix bugs without a test.
Verification Checklist
Before marking work complete:
Can't check all boxes? You skipped TDD. Start over.