Introduction

The Red-Green-Refactor cycle is the heartbeat of Test-Driven Development. This article explores each phase in detail and provides practical examples of how to implement this fundamental TDD practice.

The Three Phases

Red: Write a Failing Test

In this phase, we write a test that defines the behavior we want to implement. The test should fail because the behavior doesn't exist yet. This helps us:

  • Clarify our understanding of the requirements
  • Define the interface we want to create
  • Ensure our test is actually testing something

Green: Make the Test Pass

The goal here is to write the minimum amount of code necessary to make the test pass. This encourages:

  • Simple, focused implementations
  • Incremental development
  • Quick feedback on our approach

Refactor: Improve the Code

Once the test passes, we can safely refactor the code to improve its design while maintaining the behavior. This phase focuses on:

  • Removing duplication
  • Improving readability
  • Applying design patterns
  • Optimizing performance

Practical Example


// Red Phase
test('should calculate total price with tax', () => {
    const calculator = new PriceCalculator();
    expect(calculator.calculateTotal(100, 0.1)).toBe(110);
});

// Green Phase
class PriceCalculator {
    calculateTotal(price, taxRate) {
        return price * (1 + taxRate);
    }
}

// Refactor Phase
class PriceCalculator {
    calculateTotal(price, taxRate) {
        const tax = this.calculateTax(price, taxRate);
        return price + tax;
    }

    calculateTax(price, taxRate) {
        return price * taxRate;
    }
}
            

Best Practices

  • Keep the cycles short (2-3 minutes)
  • Write tests that are easy to understand
  • Refactor with confidence when tests are green
  • Use meaningful test names that describe behavior

Common Pitfalls

  • Writing too much code in the green phase
  • Skipping the refactor phase
  • Writing tests that are too complex
  • Not maintaining the cycle's rhythm

Conclusion

The Red-Green-Refactor cycle is a powerful tool for creating high-quality, maintainable code. By following this cycle consistently, developers can build confidence in their code and create better software.

"The act of writing a unit test is more an act of design than of verification. It is also more an act of documentation than of verification. The act of writing a unit test closes a remarkable number of feedback loops, the least of which is the one pertaining to verification of function." - Robert C. Martin