원클릭으로
test-driven-development
Use when implementing any feature or bugfix, before writing implementation code
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when implementing any feature or bugfix, before writing implementation code
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.
Use when executing implementation plans with independent tasks in the current session
Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
Use when you have a spec or requirements for a multi-step task, before touching code
Use when completing tasks, implementing major features, or before merging to verify work meets requirements
| name | test-driven-development |
| description | Use when implementing any feature or bugfix, before writing implementation code |
Related skills: Before claiming done, use
/skill:verification-before-completionto verify tests actually pass.
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.
Violating the letter of the rules is violating the spirit of the rules.
Not every change requires the same TDD approach. Determine which scenario applies:
Full TDD cycle. No shortcuts.
This is the default. If in doubt, use this scenario.
When changing code that already has test coverage:
Key: You must verify existing tests pass before and after your change. If you can't confirm test coverage, fall back to Scenario 1.
For typo fixes, config tweaks, string changes, renames:
Be honest: If the change touches logic, it's not trivial. Use Scenario 1 or 2.
The workflow monitor tracks your TDD phase and may inject warnings like:
⚠️ TDD: Writing source code (src/foo.ts) without a failing test.
When you see this, pause and assess:
The warning is a signal to think, not a hard stop.
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
Write code before the test? Delete it. Start over.
Write one minimal test showing what should happen.
Requirements:
Good:
test('retries failed operations 3 times', async () => {
let attempts = 0;
const operation = () => {
attempts++;
if (attempts < 3) throw new Error('fail');
return 'success';
};
const result = await retryOperation(operation);
expect(result).toBe('success');
expect(attempts).toBe(3);
});
Bad:
test('retry works', async () => {
const mock = jest.fn().mockRejectedValueOnce(new Error()).mockResolvedValueOnce('ok');
await retryOperation(mock);
expect(mock).toHaveBeenCalledTimes(2);
});
MANDATORY. Never skip.
Run the test. Confirm:
Test passes immediately? You're testing existing behavior. Fix the test. Test errors instead of failing? Fix the error, re-run until it fails correctly.
Write the simplest code to pass the test. Nothing more.
Don't add features, refactor other code, or "improve" beyond what the test requires. If you're writing code that no test exercises, stop.
Good: Just enough to pass the test. Bad: Adding options, config, generalization that no test asks for (YAGNI).
MANDATORY.
Run the test. Confirm:
Test fails? Fix code, not test. Other tests fail? Fix now — don't move on with broken tests.
Only after green:
Keep tests green throughout. Don't add new behavior during refactor.
Next failing test for next behavior.
| Excuse | Reality |
|---|---|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical 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. |
| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
| "Existing code has no tests" | You're improving it. Add tests for the code you're changing. |
| "This is different because..." | It's not. Follow the process. |
If you catch yourself doing any of these, stop immediately:
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 wished-for API. Write assertion first. Ask your human partner. |
| Test too complicated | Design too complicated. Simplify interface. |
| Must mock everything | Code too coupled. Use dependency injection. |
| Test setup huge | Extract helpers. Still complex? Simplify design. |
Bug found? Write failing test reproducing it. Follow TDD cycle. Test proves fix and prevents regression. Never fix bugs without a test.
When adding mocks or test utilities, read testing-anti-patterns.md in this skill directory to avoid common pitfalls:
Use workflow_reference for additional detail:
tdd-rationalizations — Extended rationalization discussiontdd-examples — More good/bad code examples, bug fix walkthroughtdd-when-stuck — Extended solutions for common blockerstdd-anti-patterns — Mock pitfalls, test-only methods, incomplete mocksProduction code → test exists and failed first (Scenario 1)
Modifying tested code → existing tests verified before and after (Scenario 2)
Trivial change → relevant tests run after (Scenario 3)
No exceptions without your human partner's permission.
When the TDD implementation cycle is complete (all tests green, code committed), mark the implement phase complete: call plan_tracker with {action: "update", status: "complete"} for the current phase.