Test-Driven Development (TDD)
Overview
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.
The Iron Law
code
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
Write code before the test? Delete it. Start over.
No exceptions:
- •Don't keep it as "reference"
- •Don't "adapt" it while writing tests
- •Don't look at it
- •Delete means delete
Implement fresh from tests. Period.
When to Use
Always:
- •New features
- •Bug fixes
- •Refactoring
- •Behavior changes
Exceptions (ask user first):
- •Throwaway prototypes
- •Generated code
- •Configuration files
Thinking "skip TDD just this once"? Stop. That's rationalization.
Red-Green-Refactor
code
┌─────────────────────────────────────────────────────────┐
│ RED → GREEN → REFACTOR │
│ Write failing Minimal code Clean up │
│ test to pass │
└─────────────────────────────────────────────────────────┘
↑ │
└─────────────────────┘
Stay GREEN
RED - Write Failing Test
- •Write test for ONE behavior
- •Test MUST fail (not compile error - real failure)
- •Failure message should be clear
Verify RED - Watch It Fail
- •Run the test
- •Verify it fails FOR THE RIGHT REASON
- •If wrong failure, fix test first
GREEN - Minimal Code
- •Write ONLY code to make test pass
- •No extra features
- •No "while I'm here" additions
- •Ugly is OK - refactor comes next
Verify GREEN - Watch It Pass
- •Run the test
- •Verify ALL tests still pass
- •If anything fails, fix immediately
REFACTOR - Clean Up
- •Improve code quality
- •Keep tests GREEN
- •Run tests after EVERY change
Good Tests
- •Fast - Milliseconds, not seconds
- •Isolated - No shared state between tests
- •Repeatable - Same result every run
- •Self-validating - Pass or fail, no interpretation
- •Timely - Written before production code
Red Flags - STOP and Start Over
| You're Doing This | Do This Instead |
|---|---|
| Writing code first | Delete it, write test |
| Test passes immediately | Test is wrong, fix it |
| Multiple behaviors in one test | Split into separate tests |
| Test depends on other tests | Isolate properly |
| "I'll add tests later" | No. Stop. Test first. |
Testing Anti-Patterns
Avoid:
- •Testing implementation - Test behavior, not internals
- •Brittle tests - Don't assert on things that shouldn't matter
- •Slow tests - Mock external dependencies
- •Flaky tests - No randomness, no timing dependencies
- •Test pollution - Clean up after yourself
Final Rule
When in doubt, write another test.