DEV Community

Nathan
Nathan

Posted on

What is REAL TDD? (It's NOT just Red-Green-Refactor)

When we talk about TDD, we often focus on technical aspects such as "writing tests first" or the "Red-Green-Refactor cycle." Given the name Test-Driven Development, this focus is only natural.

However, I want to discuss the core values that are often overlooked but are essential to practice alongside the TDD cycle.


Breaking it Down Small

In Kent Beck's book, Test-Driven Development: By Example, the most emphasized skill is the 'ability to break down tasks into small steps.' This isn’t just about small methods or classes. It’s about breaking the development process itself into tiny, granular steps—so small they might even feel "excessive."

Do these steps seem too small to you? Remember, TDD is not about taking teensy tiny steps, it's about being able to take teensy tiny steps.
- Test-Driven Development: By Example

Its true value lies in receiving real-time feedback on your current progress, as opposed to "after-the-fact testing" where you merely verify if a feature works after the entire implementation is finished.

Complex logic is never completed in a single moment. When implementing intricate logic, we instinctively repeat a cycle of running code, debugging, and checking results. TDD replaces this manual feedback loop with automated tests, providing confidence at every moment

Many developers already try to develop in "small" increments by instinct. TDD simply adds an explicit verification tool—the "test"—to that natural process. Therefore, working in small steps is not optional; it is a prerequisite for TDD.

This doesn't mean you must mechanically split everything into tiny bits every time. The point is to possess the ability to work small and adjust your pace accordingly.

Kent Beck refers to this as "shifting gears."

  • When you are confident, move fast with large strides (shift up).
  • When faced with unexpected errors or complexity, immediately decompose the steps and proceed with caution (shift down).

There is a fundamental difference between having the 'ability to break things down' and choosing your pace, versus working in large units simply because you don't know how to break them down.

By shifting gears fluidly, you escape the cycle of manual debugging and watch your test suite grow naturally.

..., so we have to change the test. That's Okay. Our guesses about the right interface are no more likely to be perfect than our guesses about the implementation.
- Test-Driven Development: By Example

Tests created this way feel different from "traditional tests." They signal that you have begun to view tests as a "Guide for Design" rather than just a "Bug-finding tool"—a clear sign that you are truly practicing TDD effectively.

To-do List

The second core value is the To-do List. This tool appears consistently throughout Beck's book. While we all use task lists, a TDD To-do List is unique for two reasons:

  1. You actually record it rather than keeping it in your head.
  2. It enables you to focus 100% on the single task at hand.

During development, it’s common to suddenly think of another fix or a brilliant new idea. The temptation to "just fix this real quick" is strong, but it leads to loss of focus. TDD discourages such indiscriminate context switching. Every new thought—a fix, a feature, or an issue to check—should be added to the To-do List immediately, allowing you to return to your current task.

In other words, you focus only on what you are doing now.

This list isn't a grand project roadmap; it consists of the granular, specific items discovered while coding—such as implementing a specific method, removing a redundant variable, or even trivial reminders that would otherwise clutter your mind.

// Todo
// Implement 3 + 2 = 5
// Implement 'equals' method
// Check if 'bar' should be removed
// Extract 'foo' method
// Decide what to eat for lunch (???)
Enter fullscreen mode Exit fullscreen mode

This is closely tied to "Breaking it Down Small." If your steps are too large, you will try to handle too many things at once, and the To-do List will lose its effectiveness.

Small step. We'll make a note of the stinkiness and move on.
- Test-Driven Development: By Example

If you can break tasks down and perform TDD entirely in your head without issues, you may continue to do so. However, as you focus and start recording new tasks, you will realize the work is often more extensive than it seemed.

Crossing items off a physical list provides a level of certainty that unrecorded thoughts cannot. The list serves as a milestone for direction and progress.

The To-do List directs you to pour all your energy into one thing at a time. In this light, the "T" in TDD might feel more like "To-do" than "Test."

Test = Behavior

What does "Test" mean in TDD? While interpretations vary, I believe it is closest to "Behavior."

This concept naturally leads to BDD (Behavior-Driven Development). BDD and TDD share the same roots. While BDD is often associated today with business scenarios, its origin was an attempt to better communicate the true essence of TDD. The "behavior" in BDD wasn't limited to scenario testing.

Dan North felt that the word "Test" hindered people from practicing the real value Kent Beck intended. He redefined it as "Behavior," which gave birth to BDD. I agree with this perspective.

For more on this:

Ironically, just as TDD was misunderstood due to the word "Test," BDD has been somewhat pigeonholed into "scenario testing" because of the strong impression of the word "Behavior."

When I first encountered TDD, I mistook it for simply writing "unit tests" first. This was a natural misunderstanding caused by the shared terminology. However, as I grew to understand TDD, I realized it is fundamentally different from traditional testing. That difference is rooted in "Breaking it Down Small" and the "To-do List."

Kent Beck wrote:

I call them “unit tests,” but they don’t match the accepted definition of unit tests very well.
- Test-Driven Development: By Example

Tests should focus on what the code is supposed to do, not how it does it, and they should remain resilient to changes in internal logic. This is what distinguishes TDD tests from typical after-the-fact unit tests.

You may also find these resources helpful:

While it may be challenging to write every test this way in practice, focusing on behavior while using tests to gain confidence in your code is a significant step forward.


Conclusion

The principles discussed here might seem like common sense. But within the context of TDD, they take on a special significance.

If you already work in small increments, TDD may feel natural. If not, simply writing a test first won't make you a TDD expert.

TDD is not just a "testing skill"; it is a "way of developing" and a "change in how you think." By defining TDD as a process of stacking small successes to gain certainty, you can begin this journey with a much lighter heart.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.