|
| 1 | +--- |
| 2 | +name: tdd |
| 3 | +description: Test-driven development — write a failing test before writing production code. Use when implementing new functionality, adding behavior, or fixing bugs during active development. |
| 4 | +--- |
| 5 | + |
| 6 | +# TDD |
| 7 | + |
| 8 | +Red. Green. Refactor. In that order, every time. |
| 9 | + |
| 10 | +## Hard Rules |
| 11 | + |
| 12 | +- No production code without a failing test first. |
| 13 | +- If production code was written before its test, delete it and start over with a failing test. |
| 14 | +- Never skip the red step. A test that has never failed proves nothing. |
| 15 | + |
| 16 | +## Cycle |
| 17 | + |
| 18 | +For each unit of behavior: |
| 19 | + |
| 20 | +1. **Red** — Write a test for the next behavior. Run it. It must fail. Read the failure message — it should describe the missing behavior. |
| 21 | +2. **Green** — Write the minimum production code to make the test pass. Nothing more. Run the test. Apply the `verify` skill. |
| 22 | +3. **Refactor** — Clean up both test and production code. Run the test again. Still green? Done. Apply the `verify` skill. |
| 23 | + |
| 24 | +Then pick the next behavior and repeat. |
| 25 | + |
| 26 | +## Rules for Each Step |
| 27 | + |
| 28 | +**Red:** |
| 29 | +- Test one behavior, not one function. Name the test after what the system should do, not what the function is called. |
| 30 | +- The test must fail for the right reason — a missing method, wrong return value, unmet condition. Not a syntax error or import failure. |
| 31 | +- If the test passes immediately, it's not testing new behavior. Delete it or pick a different behavior. |
| 32 | + |
| 33 | +**Green:** |
| 34 | +- Write the simplest code that passes. Hardcode if needed — the next test will force generalization. |
| 35 | +- Do not add code "while you're in there." If it's not required by a failing test, it doesn't exist yet. |
| 36 | +- Do not refactor during green. Pass first, clean second. |
| 37 | + |
| 38 | +**Refactor:** |
| 39 | +- Remove duplication between test and production code. |
| 40 | +- Extract only when you see real duplication, not predicted duplication. |
| 41 | +- Tests must still pass after every refactor move. Run them after each change. |
| 42 | + |
| 43 | +## Anti-Patterns |
| 44 | + |
| 45 | +| Pattern | Problem | Fix | |
| 46 | +|---|---|---| |
| 47 | +| Test-after | Code shapes the test instead of the other way around | Delete the code, write the test first | |
| 48 | +| Testing internals | Tests break on refactor, not on behavior change | Test public behavior only | |
| 49 | +| Giant red step | Multiple behaviors in one test | One assertion per behavior | |
| 50 | +| Gold-plating green | Adding code no test requires | Remove untested code | |
| 51 | +| Skipping refactor | Tech debt accumulates immediately | Refactor before the next red | |
| 52 | +| Mock-heavy tests | Tests pass but real code fails | Prefer real dependencies, mock at boundaries only | |
| 53 | + |
| 54 | +## Red Flags and Rationalizations |
| 55 | + |
| 56 | +| Rationalization | Why It's Wrong | Do Instead | |
| 57 | +|---|---|---| |
| 58 | +| "This is too simple to test first" | Simple code still needs a spec | Write the test — it'll be fast | |
| 59 | +| "I'll add the test right after" | You won't, and the code will shape the test | Test first, always | |
| 60 | +| "I need to see the design first" | The test IS the design | Let the test drive the interface | |
| 61 | +| "Mocking is too hard for this" | Difficulty mocking signals tight coupling | Fix the design, then test | |
| 62 | +| "The test would be identical to the implementation" | Then you're testing internals | Test the behavior from the outside | |
| 63 | + |
| 64 | +## Memory Integration |
| 65 | + |
| 66 | +After completing a TDD session, store reusable test patterns via the `memory` skill — e.g., test setup for a specific framework, common assertion patterns, or fixtures that were hard to get right. |
0 commit comments