Test-driven development is a workflow where you write a failing test before you write the code that makes it pass, then refactor once it passes, with the test acting as a safety net the whole time. The output looks similar to code that was tested after the fact, you end up with a test suite either way, but the process is different in a way that changes the design of the code itself. Writing the test first forces you to think about how the code will be called before you decide how it will work internally, which is the actual point of TDD, not the resulting coverage number.
What changed in 2026
- TDD adoption stayed a minority practice, honestly. Most teams write tests, fewer write them strictly first, and that gap has not closed much. The teams that do it consistently tend to do it on their highest-risk logic, not their entire codebase.
- AI pair-coding tools changed how the cycle feels. Some developers now describe the desired behavior, let an assistant draft the failing test and the implementation together, and focus their own attention on whether the test actually specifies the right behavior, which shifts the skill from typing tests to writing precise ones.
- The classicist-versus-mockist debate resurfaced as more teams hit brittle, over-mocked test suites and started asking whether their TDD practice had drifted toward testing implementation details instead of behavior.
The red-green-refactor cycle
- Red — write a test for behavior that does not exist yet. Run it. Watch it fail. This step is not optional busywork; it confirms the test can actually fail, which is the only way you know it is testing something real.
- Green — write the smallest amount of code that makes the test pass. Not the best code, not the complete feature, the smallest thing that turns the test green.
- Refactor — clean up the code you just wrote, with the passing test guaranteeing you have not changed its behavior. This is where the actual design work usually happens.
Repeat in small steps, often minutes apart. The discipline is in the size of the steps as much as the order.
Classicist versus mockist TDD
|
Classicist (Detroit school) |
Mockist (London school) |
| Isolation |
Uses real collaborators where practical |
Isolates every collaborator with a test double |
| Test focus |
Final state and outcomes |
Interactions between objects |
| Design pressure |
Toward simple, composable objects |
Toward small, well-defined interfaces between objects |
| Common failure mode |
Slower tests if real collaborators are heavy |
Brittle tests coupled to implementation details |
Neither is "correct TDD." Most experienced practitioners use both depending on what they are testing, classicist for logic-heavy code, mockist for code that primarily coordinates between other objects.
Why write the test first, specifically
The order is the entire argument for TDD over test-after. Writing the test first means you design the function interface, its name, its inputs, its return shape, from the perspective of whoever calls it, before you have any implementation to defend or work around. Writing the test after the code tends to describe whatever the code already does, including its accidental quirks, rather than what it should do.
When TDD is not worth it
- Exploratory or throwaway code, where you do not yet know what the right shape of the solution even is. Writing a precise test for a design you are still discovering just slows down the discovery.
- UI-heavy work where the fastest feedback loop is looking at the screen, not a test assertion, though the logic behind the UI often still benefits.
- One-off scripts and prototypes that will not be maintained long enough for a test suite to pay for itself.
FAQ
Is TDD the same as unit testing?
No. Unit testing is what you produce; TDD is the order you produce it in. You can unit test thoroughly without ever writing a test first, and you can practice TDD and still end up with tests at multiple levels, not only unit tests.
Does TDD guarantee good code?
No. It guarantees you have a test for every piece of behavior you deliberately drove out, and it pushes you toward simpler interfaces. It does not protect against a bad design if you are not paying attention to the refactor step.
How small should each red-green-refactor cycle be?
Small enough to take minutes, not hours. If you cannot get to red in a few minutes, the test is probably describing too much behavior at once; split it.
Is TDD compatible with behavior-driven development?
Yes, and they often pair well. Behavior-driven development operates a level up, describing behavior in business-readable terms; TDD is one way to implement that behavior test by test underneath.
Where to go next