一键导入
test-driven-development
This skill should be used when implementing new features, fixing bugs, or writing new code. Enforces RED-GREEN-REFACTOR.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
This skill should be used when implementing new features, fixing bugs, or writing new code. Enforces RED-GREEN-REFACTOR.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Canonical algorithm for consuming DECISIONS_CONTEXT index — scan index, identify relevant entries, Read full bodies on demand, cite verbatim IDs inline.
This skill should be used when evaluating implementation quality before submission, checking correctness, security, and simplicity.
This skill should be used when performing a code review to apply the standard 6-step review process.
This skill should be used when the user asks to "add accessibility", "check ARIA", "handle keyboard navigation", "add focus management", or creates UI components, forms, or interactive elements. Provides WCAG 2.2 AA patterns for keyboard navigation, ARIA roles and states, focus management, color contrast, and screen reader support.
Consumption algorithm for FEATURE_KNOWLEDGE variable — pre-computed feature context
This skill should be used when reviewing code for SOLID violations, tight coupling, or layering issues.
| name | test-driven-development |
| description | This skill should be used when implementing new features, fixing bugs, or writing new code. Enforces RED-GREEN-REFACTOR. |
| user-invocable | false |
| allowed-tools | Read, Grep, Glob |
| activation | {"file-patterns":["**/*.ts","**/*.tsx","**/*.js","**/*.jsx","**/*.py"],"exclude":["node_modules/**","dist/**","**/*.test.*","**/*.spec.*"]} |
Enforce the RED-GREEN-REFACTOR cycle for all implementation work. Tests define the design. Code satisfies the tests. Refactoring improves the design without changing behavior.
TESTS FIRST, ALWAYS
Write the failing test before the production code. No exceptions. If you catch yourself writing production code without a failing test, stop immediately, delete the production code, write the test, watch it fail, then write the minimum code to make it pass. The test IS the specification.
Write a test that describes the behavior you want. Run it. Watch it fail. The failure message IS your specification.
Describe what the code SHOULD do, not how it does it.
One behavior per test. One assertion per test (ideally).
Name tests as sentences: "returns error when email is invalid"
Checkpoint: The test MUST fail before proceeding. A test that passes immediately proves nothing.
Write the simplest production code that makes the failing test pass. No more, no less.
Hardcode first if that's simplest. Generalize when the next test forces it.
Don't write code "you'll need later." Write code the test demands NOW.
Don't optimize. Don't refactor. Don't clean up. Just pass the test.
Checkpoint: All tests pass. If any test fails, fix it before moving on.
Now clean up. Extract helpers, rename variables, simplify logic. Tests stay green throughout.
Run tests after every refactoring step.
If a test breaks during refactor, undo immediately — you changed behavior.
Apply DRY, extract patterns, improve readability.
Checkpoint: All tests still pass. Code is clean. Repeat from Step 1 for next behavior.
After each RED-GREEN-REFACTOR cycle, ALL must hold:
If any fails: you skipped TDD. Back up and redo the cycle correctly.
These are the excuses developers use to skip TDD. Recognize and reject them.
| Excuse | Why It Feels Right | Why It's Wrong | Correct Action |
|---|---|---|---|
| "I'll write tests after" | Need to see the shape first | Tests ARE the shape — they define the interface before implementation exists | Write the test first |
| "Too simple to test" | It's just a getter/setter | Getters break, defaults change, edge cases hide in "simple" code | Write it — takes 30 seconds |
| "I'll refactor later" | Just get it working now | "Later" never comes; technical debt compounds silently | Refactor now in Step 3 |
| "Test is too hard to write" | Setup is complex, mocking is painful | Hard-to-test code = bad design; the test is telling you the interface is wrong | Simplify the interface first |
| "Need to see the whole picture" | Can't test what I haven't designed yet | TDD IS design; each test reveals the next piece of the interface | Let the test guide the design |
| "Tests slow me down" | Faster to just write the code | Faster until the first regression; TDD is faster for anything > 50 lines | Trust the cycle |
| "Framework is hard to set up" | Setup is complex | One-time cost vs recurring regression cost; untested code compounds debt | Set up the framework first — that IS the work |
| "Need the architecture first" | Can't test without structure | Tests DEFINE the architecture; they reveal what interfaces are needed | Let tests drive the structure |
| "This is infrastructure, not logic" | Plumbing doesn't need tests | Infrastructure carries data; broken plumbing floods everything downstream | Test the contract, not the internals |
| "Deadline is tight, no time for tests" | Ship now, test later | Untested code ships bugs; fixing bugs under deadline is slower than TDD | TDD is faster under pressure, not slower |
See references/rationalization-prevention.md for extended examples with code.
The rationalization table above catches excuses you make before starting. These red flags catch you mid-work — thoughts that signal you are about to skip a step.
| Thought | Correction |
|---|---|
| "Let me write the implementation first, tests after" | Delete the code. Write the test. Watch it fail. Then rewrite. |
| "I need to see the shape before I can test" | The test IS the shape. It defines the interface before implementation. |
| "The test setup is too complex for this" | Complex setup = too much coupling. Simplify the design first. |
| "I'll just spike this and add tests later" | Unless the user said "spike" — you're rationalizing, not prototyping. |
| "Let me get it working, then lock it with tests" | Those tests verify your implementation, not the requirement. Backwards. |
| "I know this works, I've written it before" | Past code passed past tests. This code needs its own failing test. |
| "One more function, then I'll write the test" | STOP. Write the test for what you have now. Increments, not batches. |
Code-first (wrong):
parseConfig() — split lines, filter comments, build mapparseConfig("key=val") passesTest mirrors implementation. Edge cases stay hidden until production.
Test-first (correct):
parseConfig("# comment\nkey=val") → {key: val}parseConfig("") → empty resultparseConfig("no-equals") → errorparseConfig() to satisfy all threeTests define the contract. Implementation forced to handle edges from the start.
The difference: code-first tests verify what you happened to build. Test-first tests specify what should exist.
| Blocker | Solution |
|---|---|
| Don't know what to test first | Test the simplest input/output pair. "Given X, expect Y." Start there. |
| Test needs complex setup/state | Extract the logic into a pure function. Test that. Integrate after. |
| Behavior depends on external state (DB, API, clock) | Inject the dependency as a parameter. Pass a fake in tests. |
| Multiple behaviors tangled together | Decompose. One test = one behavior. If you can't isolate it, the design needs splitting. |
| Modifying legacy code with no tests | Write a characterization test first — a test that captures the current behavior, even if wrong. Then make your change and see what breaks. |
When implementing any feature under ambient IMPLEMENT:
user.ts → user.test.ts| Test | Don't Test |
|---|---|
| Public API behavior | Private implementation details |
| Error conditions and edge cases | Framework internals |
| Integration points (boundaries) | Third-party library correctness |
| State transitions | Getter/setter plumbing (unless non-trivial) |
When skipping TDD, never rationalize. State clearly: "Skipping TDD because: [specific reason from list above]."
/implement → Coder.