TDD — Test-Driven Development
Build features and fix bugs using the test-first red-green-refactor cycle. Tests specify observable behavior through public interfaces — they survive internal refactors.
Core philosophy
Tests should verify behavior through public interfaces, not implementation details.
Good tests read like specifications. They tell you what the system does, not how it does it.
When to use this skill
- User requests test-first development or red-green-refactor
- Building new features where behavior should drive design
- Fixing bugs where a regression test should come first
- Any work where test design should precede implementation
When not to use this skill
- Writing tests after implementation → use
- Debugging existing failures → use or
- Broad test-policy decisions → use
Anti-pattern: horizontal slices
❌ Write all tests upfront before any implementation.
This produces tests that verify imagined behavior, not actual behavior. They become insensitive to real changes because they were written before design decisions were made.
Correct approach: vertical slices
✅ One test → minimal implementation → repeat.
Each slice is a thin cut through the full behavior. Completed slices are independently demoable.
Workflow
Step 1 — Planning
Before writing any code:
- Confirm the interface design with the user
- Identify which behaviors matter most (prioritize)
- Get approval on the test approach before coding
Step 2 — Tracer bullet
Write the first test for the most important behavior:
RED: write a failing test for one behavior
GREEN: write the minimum code to make it pass
COMMIT: the behavior is now specified and verified
The tracer bullet proves the test infrastructure works and establishes the pattern.
Step 3 — Incremental loop
Repeat for each subsequent behavior:
RED → GREEN → (optional REFACTOR) → next RED
Rules:
- Write only enough code to pass the current test
- Do not anticipate future requirements
- Each test must fail before the implementation exists
- Each test must pass after the minimal implementation
Step 4 — Refactor
After all behaviors are tested and passing:
- Extract duplication into shared helpers
- Deepen modules (simple interface, rich behavior)
- Run tests after each refactor step
- Never refactor while tests are red
Per-cycle checklist
Before moving to the next cycle, verify the test:
Example
typescript
// RED: write the failing test first
test('formats currency with symbol', () => {
expect(formatCurrency(1000, 'USD')).toBe('$1,000.00')
})
// GREEN: write minimal passing code
function formatCurrency(amount: number, currency: string): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
}).format(amount)
}
// REFACTOR if needed, then move to next behavior
Instructions
- Identify the task trigger and expected output.
- Follow the workflow steps in this skill from top to bottom.
- Validate outputs before moving to the next step.
- Capture blockers and fallback path if any step fails.
Examples
- Example: Apply this skill to a small scope first, then scale to full scope after validation passes.
Best practices
- Keep outputs deterministic and auditable.
- Prefer small reversible changes over broad risky edits.
- Record assumptions explicitly.
References
- Project standards:
.agent-skills/skill-standardization/SKILL.md
- Validator script:
.agent-skills/skill-standardization/scripts/validate_skill.sh