Test-Driven Development Workflow | Red-Green-Refactor
Implement TDD with the red-green-refactor cycle. GitScrum tracks TDD adoption metrics and measures impact on bug rates and velocity.
10 min read
Tests drive design. GitScrum helps teams track TDD adoption and measure the impact of test-first practices on quality and velocity.
TDD Fundamentals
The Red-Green-Refactor Cycle
TDD CYCLE:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β THE CYCLE: β
β ββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββ β
β β β β
β β ββββββββββ β β
β β β RED β Write failing test β β
β β βββββ¬βββββ β β
β β β β β
β β βΌ β β
β β ββββββββββ β β
β β β GREEN β Make it pass β β
β β βββββ¬βββββ (minimal code) β β
β β β β β
β β βΌ β β
β β ββββββββββ β β
β ββββββ€REFACTORβ Improve design β β
β ββββββββββ (tests still pass) β β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β STEP 1 - RED: β
β Write a test for behavior that doesn't exist yet β
β Run it β It fails (proves test works) β
β β
β STEP 2 - GREEN: β
β Write just enough code to pass the test β
β Don't over-engineer, don't optimize β
β Just make it work β
β β
β STEP 3 - REFACTOR: β
β Now improve the code β
β Remove duplication, clarify names, improve design β
β Tests ensure you didn't break anything β
β β
β REPEAT for each small piece of behavior β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Example Workflow
TDD in Practice
TDD EXAMPLE:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β FEATURE: Calculate order total with discount β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β STEP 1 - RED (Write failing test): β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β test('calculates total with 10% discount', () => { ββ
β β const order = new Order([ ββ
β β { price: 100 }, ββ
β β { price: 50 } ββ
β β ]); ββ
β β order.applyDiscount(0.1); ββ
β β expect(order.total()).toBe(135); ββ
β β }); ββ
β β ββ
β β RUN β β FAIL (Order doesn't exist) ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β STEP 2 - GREEN (Make it pass): β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β class Order { ββ
β β constructor(items) { ββ
β β this.items = items; ββ
β β this.discount = 0; ββ
β β } ββ
β β ββ
β β applyDiscount(rate) { ββ
β β this.discount = rate; ββ
β β } ββ
β β ββ
β β total() { ββ
β β const subtotal = this.items.reduce( ββ
β β (sum, item) => sum + item.price, 0 ββ
β β ); ββ
β β return subtotal * (1 - this.discount); ββ
β β } ββ
β β } ββ
β β ββ
β β RUN β β
PASS ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β STEP 3 - REFACTOR (Improve): β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β’ Extract subtotal calculation ββ
β β β’ Add validation ββ
β β β’ Improve naming ββ
β β β’ Run tests β Still passing β
ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β NEXT: Write another test for next behavior β
β (e.g., maximum discount, negative prices, etc.) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Benefits
Why TDD Works
TDD BENEFITS:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β BETTER DESIGN: β
β ββββββββββββββ β
β Writing tests first forces you to think about: β
β β’ How code will be used (API design) β
β β’ What the code should do (requirements) β
β β’ How to make it testable (loose coupling) β
β β
β Result: Cleaner, more modular code β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β CONFIDENCE: β
β βββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β WITHOUT TESTS: ββ
β β "Does this change break something?" ββ
β β β Manual testing, uncertainty, fear ββ
β β ββ
β β WITH TDD: ββ
β β "Does this change break something?" ββ
β β β Run tests β Know in seconds ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β DOCUMENTATION: β
β ββββββββββββββ β
β Tests document what code should do β
β Executable documentation that can't go stale β
β New developers read tests to understand behavior β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β LESS DEBUGGING: β
β βββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β WRITE CODE FIRST: ββ
β β Write β Test manually β Find bugs β Debug β Fix ββ
β β Time: 2 hours coding + 3 hours debugging = 5 hours ββ
β β ββ
β β TDD: ββ
β β Test β Code β Pass β Repeat ββ
β β Time: 3 hours (includes tests) + 30 min debug ββ
β β ββ
β β Bugs caught immediately, not hours later ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Test Types
What to Test
TESTING PYRAMID WITH TDD:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β /\ β
β / \ E2E Tests β
β / UI \ (Few, slow, broad) β
β /ββββββ\ β
β / \ Integration Tests β
β / Service \ (Some, medium speed) β
β /ββββββββββββ\ β
β / \ Unit Tests β
β / Unit \ (Many, fast, focused) β
β /ββββββββββββββββββ\ β
β β
β TDD FOCUS: β
β ββββββββββ β
β Primarily unit tests β
β Fast feedback loop β
β Test one thing at a time β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β WHAT TO TEST IN TDD: β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β ββ
β β β
BUSINESS LOGIC: ββ
β β β’ Calculations ββ
β β β’ Validation rules ββ
β β β’ State transitions ββ
β β β’ Domain behavior ββ
β β ββ
β β β οΈ INTEGRATION POINTS: ββ
β β β’ API contracts ββ
β β β’ Database queries (integration tests) ββ
β β β’ External service calls (mocked in unit tests) ββ
β β ββ
β β β DON'T TDD: ββ
β β β’ Framework code (already tested) ββ
β β β’ Simple getters/setters ββ
β β β’ UI layout (use other testing) ββ
β β β’ Throwaway prototypes ββ
β β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Team Adoption
Implementing TDD
ADOPTING TDD:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β PHASE 1: LEARN (Week 1-2) β
β βββββββββββββββββββββββββ β
β β’ TDD kata/workshop β
β β’ Practice on toy problems β
β β’ Pair with experienced TDD practitioner β
β β’ Read/watch TDD resources β
β β
β PHASE 2: NEW CODE (Week 3-4) β
β ββββββββββββββββββββββββββββ β
β β’ Apply TDD to new features β
β β’ Start with simple stories β
β β’ Pair programming recommended β
β β’ Expect slower at first β
β β
β PHASE 3: EXPAND (Month 2+) β
β ββββββββββββββββββββββββββ β
β β’ More complex features β
β β’ Add tests when modifying existing code β
β β’ Develop team testing patterns β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β COMMON CHALLENGES: β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β ββ
β β "It's slower!" ββ
β β β Initially yes. Track time saved in debugging. ββ
β β Long-term velocity increases. ββ
β β ββ
β β "I don't know what test to write" ββ
β β β Start with the simplest behavior. ββ
β β What's the most basic thing it should do? ββ
β β ββ
β β "How do I test this complex thing?" ββ
β β β If it's hard to test, design might need work. ββ
β β TDD pushes you toward better design. ββ
β β ββ
β β "We have too much legacy code" ββ
β β β TDD new code. Add tests when touching old code. ββ
β β Gradual improvement over time. ββ
β β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Best Practices
TDD Guidelines
TDD BEST PRACTICES:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β TEST NAMING: β
β ββββββββββββ β
β β test1(), testCalculate() β
β β
β β
'should calculate total with tax' β
β β
'returns error when email invalid' β
β β
'applies discount only to eligible items' β
β β
β Name describes expected behavior β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ONE ASSERTION PER TEST: β
β ββββββββββββββββββββββββ β
β β β
β test('order works', () => { β
β expect(order.total()).toBe(100); β
β expect(order.itemCount()).toBe(5); β
β expect(order.isValid()).toBe(true); β
β }); β
β β
β β
β
β test('calculates correct total', () => {...}); β
β test('counts items correctly', () => {...}); β
β test('validates order', () => {...}); β
β β
β Easier to identify failures β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β SMALL STEPS: β
β ββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β DON'T: Write complex test requiring 100 lines of code ββ
β β DO: Write test requiring 5-10 lines of code ββ
β β ββ
β β Smaller steps = faster feedback = fewer bugs ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β DON'T SKIP REFACTOR: β
β ββββββββββββββββββββ β
β Green is not done! β
β Refactor before moving to next test β
β Technical debt accumulates if you skip this β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Measuring TDD
Tracking Adoption
TDD METRICS:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β ADOPTION METRICS: β
β βββββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β TDD ADOPTION - Q1 2025 ββ
β β ββ
β β Stories using TDD: ββ
β β Jan: 20% ββββ ββ
β β Feb: 45% βββββββββ ββ
β β Mar: 68% βββββββββββββ ββ
β β ββ
β β Test coverage trend: ββ
β β Jan: 45% ββ
β β Feb: 58% ββ
β β Mar: 72% ββ
β β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β QUALITY IMPACT: β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β BUGS IN PRODUCTION: ββ
β β ββ
β β Before TDD (2024): 8 bugs/sprint average ββ
β β After TDD (2025): 3 bugs/sprint average (-63%) ββ
β β ββ
β β REWORK TIME: ββ
β β ββ
β β Before: 25% of sprint on bug fixes ββ
β β After: 10% of sprint on bug fixes (-60%) ββ
β β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β VELOCITY: β
β βββββββββ β
β Short-term: May dip 10-20% during learning β
β Long-term: Often increases as debugging decreases β
β β
β Track both to show the investment pays off β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ