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
Member discussion: