| name | test-driven-development |
| description | Red-green-refactor TDD implementation cycle |
| methodology | tdd |
Test-Driven Development Skill
Implement code using the red-green-refactor cycle. This skill is used by the
Implementer to write code driven by failing tests.
Core Principle
Write the MINIMUM code to make a failing test pass. No more. Then refactor
to improve quality without changing behavior.
Steps
Phase 1: RED — Write a failing test
- Pick the next test from the implementation plan.
- Write the test code first, before any implementation.
- Run the test: it MUST fail (red). If it passes without implementation, the
test is not testing the right thing.
- Read the failure message — it tells you exactly what to implement.
Phase 2: GREEN — Make the test pass
- Write the MINIMUM implementation to make the failing test pass.
- No extra logic, no anticipated future use cases
- Hardcoding is acceptable at this stage if it makes the test pass
- Copy-paste is acceptable if it moves quickly to green
- Run the test: it MUST pass (green).
- Run ALL tests: ensure no regressions.
- Do NOT refactor yet.
Phase 3: REFACTOR — Improve the code
- Only after tests are green, improve code quality.
- Remove duplication
- Improve naming
- Extract helper functions
- Simplify logic
- Run tests after every change — refactoring must not break anything.
- Do NOT add new behavior during refactoring.
- When satisfied, move to the next test in the plan.
Rules
- Never skip the red phase — always write the test first
- Never write more code than needed to pass the current test
- Never refactor while red — only refactor on green
- Commit after each green-refactor cycle (small, frequent commits)
- If a test is hard to write, it signals a design problem — fix the design
Test Structure
Follow table-driven tests for multiple scenarios:
func TestFunctionName(t *testing.T) {
tests := []struct {
name string
input InputType
want OutputType
wantErr bool
}{
{name: "happy path", input: ..., want: ..., wantErr: false},
{name: "empty input", input: ..., want: ..., wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := FunctionName(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("unexpected error: %v", err)
}
if got != tt.want {
t.Errorf("got %v, want %v", got, tt.want)
}
})
}
}
Output Format
For each RED-GREEN-REFACTOR cycle, produce:
- The failing test code
- The minimal implementation
- Any refactoring applied
- Confirmation that all tests pass