Grasping the three laws of Test-Driven Development (TDD) is crucial for producing clean, stable, and consistent code. By embracing these principles, developers can reduce time spent debugging and focus more on refining their codebase. It provides a framework that developers use to build a test suite, write implementation code, and optimize their codebase in short development cycles.
It's hard to tell how they work just from reading them, but the rules but the do one very important thing - they constrain us to handling only one change at a time!
The Three Laws of TDD
- You are not allowed to write any production code unless it is to make a failing unit test pass.
- You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
- With the added caveat that you may only refactor code when all test are green!
One important thing to note is that the three laws of TDD manifest as the Red, Green, Refactor Cycle as seen below.
Figure 1: Red, Green, Refactor TDD Cycle
Think about what you want to develop
The Red phase serves as the starting point of the Red-Green-Refactor cycle, setting the stage for a systematic and goal-oriented development process. The primary objective of this phase is to create a test that guides the implementation of a specific feature. The test will pass only when its expectations are met, ensuring that each step of the cycle is meaningful and contributes to the overall quality of the code.
Think about how to make your tests pass
In the Green phase of the Red-Green-Refactor cycle, the primary objective is to develop code that enables the test to pass. At this stage, the focus is on finding a solution rather than optimizing the implementation. A great tool to use when drive towards a solution are the green bar patterns.
This approach allows developers to prioritize problem-solving and functionality, ensuring that the code meets the test's expectations before further refinement.
Read your code and think about how to improve your existing implementation or your tests
During the Refactor phase, the code remains "in the green," having already passed the test. This stage provides an opportunity to refine and optimize the implementation for improved efficiency and readability. When considering refactoring the test suite, developers should always keep in mind the characteristics of a good test. In terms of refactoring implementation code, the focus should be on achieving the same output using more descriptive or faster code, ultimately enhancing the overall quality.
While it may not always be necessary to refactor your codebase, it's important to thoroughly evaluate the need for refinements when you're "in the green." Before transitioning back to the Red phase, ask yourself the following questions to determine whether a refactor is warranted:
- Are my tests isolated? There are no cross dependencies in data setup. That is Test A modifies the data, then Test B depends upon the modifications to pass.
- Can I make my implementation code more descriptive? Can naming be improved? Are there concepts to pull out in to well named methods or classes?
- Can I implement something more efficiently?
- Does my test suite provide reliable feedback?
- Does my test suite provide good coverage? Have you considered the boundaries and equivalence partitions of the problem?