Test-Driven Development
Comprehensive methodology for test-first software development using the Red-Green-Refactor cycle to build reliable, verified code through systematic testing discipline.
Essential for developers committed to code quality who want to prevent bugs before production and ensure every feature is properly tested.
Core Principle
"If you didn't watch the test fail, you don't know if it tests the right thing."
This fundamental rule ensures tests genuinely verify behavior rather than merely documenting existing code.
Red-Green-Refactor Cycle
The Three Phases
đź”´ RED Phase:
- Write minimal failing test demonstrating required behavior
- Use clear, descriptive test names
- Test one behavior per test
- Prefer real code over mocks when possible
âś… GREEN Phase:
- Implement only minimal code to pass the test
- Avoid feature expansion beyond requirements
- Don't refactor other code yet
- Focus on simplicity
♻️ REFACTOR Phase:
- Clean up code while tests stay green
- Remove duplication
- Improve naming
- Extract helper functions
Mandatory Verification Steps
After Each Phase:
RED → Verify test FAILS for expected reasons
- Not due to syntax errors
- Not testing existing functionality
- Fails with meaningful error message
GREEN → Verify ALL tests PASS
- New test passes
- No regressions in other tests
- Clean test output
REFACTOR → Verify tests REMAIN GREEN
- All tests still passing
- No behavior changes
- Improved code structure
When to Apply TDD
Use Consistently For:
- New features
- Bug fixes
- Refactoring
- Any behavior changes
Exceptions:
- Require explicit team lead approval
- Rare and documented
Common Rationalizations (and Rebuttals)
| Excuse | Why It's Wrong |
|---|---|
| "I'll test after implementing" | Tests-after documents what code does, not what it should do. You lose the design feedback. |
| "Code is too simple to test" | Simple code breaks too. Testing simple code takes minimal effort. |
| "I've manually tested it" | Manual tests lack systematic verification and reproducibility. |
| "Deleting code feels wasteful" | Unverified code is technical debt, not an asset. |
| "Just this once..." | Every exception weakens discipline. Rules matter most under pressure. |
Red Flags
Stop Development Immediately If:
- Writing production code before tests
- Tests pass on first run (didn't verify they can fail)
- "I'll test it later" mentality
- Keeping pre-test code "as reference"
- Skipping verification steps
- Testing after implementation
These indicate you've left TDD discipline.
Practical Example: Bug Fix
Scenario: Empty email field incorrectly accepted
1. Write Failing Test:
test('rejects empty email', () => {
const result = validateEmail('');
expect(result.valid).toBe(false);
expect(result.error).toBe('Email is required');
});
2. Verify It Fails:
npm test path/to/test.test.ts
# Should fail with: Expected false, got true
3. Implement Validation:
function validateEmail(email: string) {
if (!email) {
return { valid: false, error: 'Email is required' };
}
// ... existing validation
}
4. Verify All Tests Pass:
npm test
# All tests green âś“
Key Distinctions
TDD vs. Testing After
TDD (Test-First):
- Answers: "What should this do?"
- Discovers edge cases during design
- Tests drive implementation
- Prevents over-engineering
Testing After:
- Answers: "What does this do?"
- Discovers edge cases post-implementation
- Tests document existing code
- Encourages feature bloat
Real Code vs. Mocks
Prefer Real Implementations
Use Real Code When:
- Simple, fast operations
- No external dependencies
- Easier to understand
- More reliable tests
Use Mocks When:
- External API calls
- Database operations
- Slow file I/O
- Non-deterministic behavior
Verification Checklist
Before considering work complete:
- Every function has a test written first
- Each test failed for expected reasons
- Minimal code implemented for each test
- All tests passing with clean output
- Edge cases covered
- Error conditions tested
- No test skipped or ignored
- Code refactored with tests green
The Spirit of the Rules
"Violating the letter of the rules is violating the spirit of the rules."
TDD's test-first ordering isn't arbitrary ritual:
- Discovers design problems before implementation
- Identifies edge cases early
- Prevents scope creep by focusing on requirements
- Ensures testability from the start
The sequence enables these benefits—changing the order loses them.
Common Patterns
Testing New Features
- Write test for simplest case
- Watch it fail
- Implement minimal code
- Add test for next case
- Repeat until feature complete
Fixing Bugs
- Write test reproducing the bug
- Verify test fails (confirms bug exists)
- Fix with minimal code
- Verify test passes
- Check for similar bugs
Refactoring
- Ensure all tests green
- Make one small change
- Run tests (should stay green)
- Repeat until refactoring complete
Team Adoption
Getting Teams On Board:
- Pair program with TDD
- Code review for test-first evidence
- Celebrate catching bugs in tests
- Share TDD success stories
- Make it non-negotiable for critical code
About This Skill
This skill was created by obra as part of the Superpowers Skills Collection. Obra is an established contributor creating high-quality development workflow skills.
Explore the collection to discover complementary skills for systematic debugging, brainstorming, and git workflows!
Comprehensive TDD methodology emphasizing test-first development with the Red-Green-Refactor cycle for building reliable, verified software.