Have you ever wondered about the differences between unit testing and TDD? Or TDD and Test-First? Or even the relationship of all of this to the agile methodologies? Are these kinds of tests manual or automated? And, for goodness’ sake, what is it with all the “DD”-ending acronyms?
If the paragraph above accurately describes you and your relationship with these topics don’t despair because we’ve got your back. Today’s post is your guide to the different testing techniques and methodologies available.
After reading this article, you will:
- understand what unit testing is about;
- know about TDD and BDD, understanding their place in the software development landscape and how they relate to each other; and
- learn about the tools and sources of information at your disposal.
Let’s get started.
First Things First: Automated Software Testing Is a Thing
It may come as a surprise to some of you that I even felt the need to add such a section. If that’s the case for you, feel free to skip it. Believe it or not, there are many developers for whom the notion of automated software testing is completely alien.
If you go to Wikipedia, you’ll see that the topic of automated software testing is huge. Really, really huge. There are many different kinds of automated testing, each one of them catering to some specific need or even audience.
Nowadays, when people talk about automated testing (or simply testing), more often than not they mean unit testing, which many people consider to be the most important type.
Unit Testing: The Groundwork for All That’s to Come
There are many possible and somewhat conflicting definitions for unit testing. I particularly like Roy Osherove’s definition:
A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behavior of that unit of work.
Let’s try to parse this sentence. Roy starts out by claiming that “a unit test is an automated piece of code.” In other words, it’s a program. A unit test is an automated test. It’s a program that tests your program!
Let’s move on. The definition goes on to state that a unit test “invokes a unit of work in the system.” Let’s not worry for now about what a unit of work is; instead, focus on the word “invokes.” Our automated unit test invokes whatever it’s testing: no human intervention is needed.
Finally, we see that the unit test then “checks a single assumption about the behavior of that unit of work.” Again, don’t worry about what a unit of work is or isn’t. Instead notice that, once again, no human intervention is needed, since the test itself checks its result.
What can we get from this definition? In short, a unit test is a program that:
- invokes some piece of code;
- compares the result of said invocation with some desired behavior; and
- accomplishes all of that without human intervention.
And how does all of that work in practice? In short, we can say that you write and run unit tests with the help of a test framework. In the Java world, for instance, the most well-known test framework is JUnit, while in .NET-land you’d probably use NUnit or xUnit.net.
And What About the Unit?
In the previous section, I kept telling you not to worry about what the unit (or “unit of work,” as Roy Osherove puts it) means in the context of unit testing. Now it’s time to worry. So…what is this unit thing?
Well…it’s kind of hard to say. One of the most controversial things about the whole unit testing thing is the definition of a “unit” itself.
This is what Wikipedia has to say about the issue:
Intuitively, one can view a unit as the smallest testable part of an application. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method.
And what about Roy Osherove’s definition? Let’s see:
A unit of work is a single logical functional use case in the system that can be invoked by some public interface (in most cases). A unit of work can span a single method, a whole class or multiple classes working together to achieve one single logical purpose that can be verified.
In my view, what all of those definitions have in common is that they’re somewhat vague. It doesn’t sound that useful to me to go to a beginner and say: “What is a unit? Easy: a unit is a class, except when it’s just a method. Oh, I forgot to mention: it can also be a group of several classes.”
For that reason, I tend to say that a unit is just a method of the class under test. It might be somewhat reductionist, maybe not totally correct, but it sure is pragmatic. And of course: your definition doesn’t have to remain the same forever. It can—and should—evolve as you learn and gain more experience with all of this.
TDD: Unit Testing Driving You to Better Design
TDD means Test Driven Development. It’s a software development methodology in which unit tests are used to drive the development of the application.
TDD was created/rediscovered by Kent Beck, who released Test Driven Development: By Example in 2002. TDD has gained a lot of popularity since then, in part due to being one of the key engineering practices of the Extreme Programming methodologies.
Great, but How Does TDD Work?
The process of applying TDD is itself very simple. You should write code following what’s called the “red-green-refactor” cycle:
- Before starting to implement a feature, you should write a test for it.
- The test will obviously fail, since the thing being tested doesn’t exist.
- You then proceed to write the minimum amount of code that will make the test pass. Cheating (i.e., taking a shortcut that doesn’t really solve the problem but causes the test to pass) is not only allowed, but actively encouraged.
- As soon as the testing passes, it’s time for refactoring (i.e., improving the code without changing its behavior).
Proponents of TDD claim that by following this process you’ll achieve a simpler design, creating modules that are by definition low coupled and having more confidence to make changes to the code in the future, since you’ll have an automated test suite covering all of the code.
BDD: Behavior-Driven Development
BDD means Behavior-Driven Development and was introduced in 2006 by Dan North. Dan states that BDD evolved as a response to TDD, an attempt to address issues he had when trying to apply the TDD process.
BDD emphasizes the need to include not only software developers but also non-technical people, such as business analysts, in the process of defining the tests. By the way: the term “test” itself isn’t that welcome anymore. Under the light of BDD, we should think of requirements. Requirements should follow the template:
- Given some initial context (the givens),
- When an event occurs,
- then ensure some outcomes.
And How Do Unit Testing, TDD, and BDD Relate to Each Other?
How do all of these pieces fit in the puzzle? What are the relationships between all these things?
- Unit testing is a type of automated testing. You can write unit testing without using TDD or BDD, just by writing the tests after the production code.
- TDD is a software development methodology, in which the developer writes code in very short cycles, always starting with a failing test.
- BDD can be thought of as a “flavor” of TDD, in which the application’s development is driven by its behavior, described in the forms of human-readable requirements that must be later converted to executable tests.
All three of the techniques (but especially unit testing and TDD) presented in today’s post remain more or less controversial to this day. See some examples:
- Test Introduced Damage
- TDD? Waste of time!
- Test-Driven Development? Give me a break…
- Write Tests. Not Too Many. Mostly integration.
Are these techniques worth your time? My personal opinion has changed over the years but my current take is: write automated tests for your code. Mostly unit tests, but also other types (while being aware that there might be exceptions to that rule). The process that you use in order to write said tests shouldn’t matter that much.
Are TDD and BDD worth your time? Definitely. Do they also provide challenges and have their own shortcomings and limitations? Of course. There’s no silver bullet in our industry. The only way is to read a lot and practice a lot in the hopes that, when the time comes, you’ll be able to make informed decisions. Read more on testing techniques like unit testing, TDD, and BDD.