$npx -y skills add stevesolun/ctx --skill tddTest-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
| 1 | # Test-Driven Development |
| 2 | |
| 3 | ## Philosophy |
| 4 | |
| 5 | **Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't. |
| 6 | |
| 7 | **Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure. |
| 8 | |
| 9 | **Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior. |
| 10 | |
| 11 | See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines. |
| 12 | |
| 13 | ## Anti-Pattern: Horizontal Slices |
| 14 | |
| 15 | **DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code." |
| 16 | |
| 17 | This produces **crap tests**: |
| 18 | |
| 19 | - Tests written in bulk test _imagined_ behavior, not _actual_ behavior |
| 20 | - You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior |
| 21 | - Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine |
| 22 | - You outrun your headlights, committing to test structure before understanding the implementation |
| 23 | |
| 24 | **Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it. |
| 25 | |
| 26 | ``` |
| 27 | WRONG (horizontal): |
| 28 | RED: test1, test2, test3, test4, test5 |
| 29 | GREEN: impl1, impl2, impl3, impl4, impl5 |
| 30 | |
| 31 | RIGHT (vertical): |
| 32 | RED→GREEN: test1→impl1 |
| 33 | RED→GREEN: test2→impl2 |
| 34 | RED→GREEN: test3→impl3 |
| 35 | ... |
| 36 | ``` |
| 37 | |
| 38 | ## Workflow |
| 39 | |
| 40 | ### 1. Planning |
| 41 | |
| 42 | When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching. |
| 43 | |
| 44 | Before writing any code: |
| 45 | |
| 46 | - [ ] Confirm with user what interface changes are needed |
| 47 | - [ ] Confirm with user which behaviors to test (prioritize) |
| 48 | - [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation) |
| 49 | - [ ] Design interfaces for [testability](interface-design.md) |
| 50 | - [ ] List the behaviors to test (not implementation steps) |
| 51 | - [ ] Get user approval on the plan |
| 52 | |
| 53 | Ask: "What should the public interface look like? Which behaviors are most important to test?" |
| 54 | |
| 55 | **You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case. |
| 56 | |
| 57 | ### 2. Tracer Bullet |
| 58 | |
| 59 | Write ONE test that confirms ONE thing about the system: |
| 60 | |
| 61 | ``` |
| 62 | RED: Write test for first behavior → test fails |
| 63 | GREEN: Write minimal code to pass → test passes |
| 64 | ``` |
| 65 | |
| 66 | This is your tracer bullet - proves the path works end-to-end. |
| 67 | |
| 68 | ### 3. Incremental Loop |
| 69 | |
| 70 | For each remaining behavior: |
| 71 | |
| 72 | ``` |
| 73 | RED: Write next test → fails |
| 74 | GREEN: Minimal code to pass → passes |
| 75 | ``` |
| 76 | |
| 77 | Rules: |
| 78 | |
| 79 | - One test at a time |
| 80 | - Only enough code to pass current test |
| 81 | - Don't anticipate future tests |
| 82 | - Keep tests focused on observable behavior |
| 83 | |
| 84 | ### 4. Refactor |
| 85 | |
| 86 | After all tests pass, look for [refactor candidates](refactoring.md): |
| 87 | |
| 88 | - [ ] Extract duplication |
| 89 | - [ ] Deepen modules (move complexity behind simple interfaces) |
| 90 | - [ ] Apply SOLID principles where natural |
| 91 | - [ ] Consider what new code reveals about existing code |
| 92 | - [ ] Run tests after each refactor step |
| 93 | |
| 94 | **Never refactor while RED.** Get to GREEN first. |
| 95 | |
| 96 | ## Checklist Per Cycle |
| 97 | |
| 98 | ``` |
| 99 | [ ] Test describes behavior, not implementation |
| 100 | [ ] Test uses public interface only |
| 101 | [ ] Test would survive internal refactor |
| 102 | [ ] Code is minimal for this test |
| 103 | [ ] No speculative features added |
| 104 | ``` |