

It might be surprising for you to learn that test-driven development (TDD) isn’t a software testing technique, but that’s the truth. What is TDD, then?
TDD is a software development methodology in which automated testing plays a core role. But what does that mean in practice? What is TDD used for, what are its benefits, and should you adopt it?
Learn the answers to these questions and more in our guide.
Test-Driven Development (TDD) is a technique for building software that guides software development by writing tests
What is test-driven development (TDD)?
Definition
Over the years, people have been defining TDD in a lot of ways, including some wrong ones. Let’s start our guide with a clear, succinct, and, most importantly, correct definition:
Test-Driven Development (TDD) is a technique for building software that guides software development by writing tests. It was developed by Kent Beck in the late 1990’s as part of Extreme Programming. In essence we follow three simple steps repeatedly:
- Write a test for the next bit of functionality you want to add.
- Write the functional code until the test passes.
- Refactor both new and old code to make it well structured.
Martin Fowler, Test-Driven Development
Fowler’s definition clearly states that TDD “is a technique for building software” rather than being a technique for testing software. Yes, as a result of doing TDD, you’ll end up with a comprehensive suite of automated tests—and that is, in itself, one advantage of adopting the practice. More on that later.
But the real goal of TDD is to use tests to guide your development in ways that result in clean, maintainable code, as well as a high degree of confidence in the correctness of the developed features.
History
From Martin Fowler’s definition above, we can see that Kent Beck created TDD in the 1990s. In 2002, he launched the book Test-Driven Development: By Example, which is a practical manual of how to apply the technique.
Other authors released more books and articles, expanding and building upon the foundation Kent Beck created. Different styles and schools of thought emerged for TDD, and it even spawned related methodologies, such as BDD (behavior-driven development) and ATDD (acceptance-test-driven development).
TDD has since enjoyed significant adoption across the industry, and to this day is an important topic of discussion in conferences and developer communities.
How does TDD fit into Agile development?
Agile is an umbrella term that covers many software development methodologies, of which one of the main ones is XP, or Extreme Programming. Kent Beck developed Extreme Programming while working as project lead for the Chrysler Comprehensive Compensation System (C3) payroll project.
XP is different from many other Agile flavors in the sense that it’s concerned about software engineering best practices. It dictates how software developers must do their work, advocating for practices like pair programming, refactoring, and TDD.
If you’re using a compiled language such as C# or Java, the code from your test won’t even compile
Core principles of test-driven development
How does TDD work in practice? From Fowler’s definition that we covered earlier, it’s possible to see that TDD requires writing tests before the functionality exists. Here’s the same workflow, with a bit more detail:
- Write a list of the test scenarios you want to cover
- Turn exactly one item on the list into an actual, concrete, runnable test
- Change the code to make the test (& all previous tests) pass (adding items to the list as you discover them)
- Optionally refactor to improve the implementation design
- Until the list is empty, go back to #2
Kent Beck, Canon TDD
As you can see, development starts by writing a test. Of course, the test will fail because the desired feature doesn’t exist. If you’re using a compiled language such as C# or Java, the code from your test won’t even compile. You then write just the minimum amount of code you need to make the test pass, ensuring previous tests (if any) continue to pass.
What kind of tests are we talking about here, anyway? Though this can vary, tests in the context of TDD almost always refer to unit testing.
But going back to TDD’s flow: What’s the point of working in this seemingly backward way?
Benefits of TDD
In short, the TDD rules, when applied, force you to think of the interface and not the implementation when first developing a feature, ensuring design is simple and less coupled. Here’s Fowler again:
Writing the test first […] provides two main benefits. Most obviously it’s a way to get SelfTestingCode, since we can only write some functional code in response to making a test pass. The second benefit is that thinking about the test first forces us to think about the interface to the code first. This focus on interface and how you use a class helps us separate interface from implementation, a key element of good design that many programmers struggle with.
Martin Fowler, Test-Driven Development
In his book, Beck expands on the benefits:
Assuming for the moment that such a programming style is possible, it might be possible to dramatically reduce the defect density of code and make the subject of work crystal clear to all involved. If so, then writing only that code which is demanded by failing tests also has social implications.
If the defect density can be reduced enough, then quality assurance (QA) can shift from reactive work to proactive work.
If the number of nasty surprises can be reduced enough, then project managers can estimate accurately enough to involve real customers in daily development.
If the topics of technical conversations can be made clear enough, then software engineers can work in minute-by-minute collaboration instead of daily or weekly collaboration.
Again, if the defect density can be reduced enough, then we can have shippable software with new functionality every day, leading to new business relationships with customers.
Kent Beck, Test-Driven Development: By Example
TDD challenges
For skeptics, TDD is one of those things that sound too good to be true. The truth is that applying TDD is a skill that takes time and effort to master. If you intend to give TDD a try, expect to face some common challenges:
Lack of unit testing knowledge
Remember, TDD isn’t synonymous with unit testing. If team members lack unit testing skills, including knowing how to use the unit testing framework and test runner for their language, adopting TDD will be tough.
Don’t attempt to learn unit testing and TDD at the same time; first, make sure everyone is comfortable writing tests. Then, start introducing TDD.
If a team only works with brownfield projects—that is, existing legacy projects—applying TDD is going to be difficult
Only brownfield projects
If a team only works with brownfield projects—that is, existing legacy projects—applying TDD is going to be difficult. Those projects most likely weren’t built with testability in mind, meaning that you won’t even have the infrastructure in place to start writing tests.
For projects like this, you must carefully refactor the code and start adding tests. Working Effectively With Legacy Code, by Michael Feathers, is a great book that can help in these scenarios.
Difficulty testing certain types of code
UI code and database code are examples of areas of a codebase that might be difficult or awkward to use TDD for.
Test maintenance burden
Over time, the size of a test suite tends to grow. Poorly written tests become brittle and break frequently as the codebase evolves, especially tests that are tightly coupled to implementation details of the tested code.
Cultural resistance
At the end of the day, the biggest challenge is simply resistance to change. Consciously or not, many developers will reject the shift in mindset that is necessary to work in this radically new way. The learning and adapting curve might be steep, as well.
Conclusion
As mentioned earlier, TDD isn’t a testing technique, but a building one. If applied correctly, it can lead to clean, maintainable code that gives developers and users a high degree of confidence about code correctness.
Since TDD isn’t a testing technique, it doesn’t replace traditional testing approaches. Yes, you’ll still need performance testing, end-to-end testing, contract testing, and any other forms of testing that are applicable to your context. TDD is an additional tool that can make your testing more effective and robust.
This post was written by Carlos Schults. Carlos is a skilled software engineer and an accomplished technical writer for various clients. His passion is to get to the bottom (the original source) of things and captivate readers with approachable and informative technical content.
