New feature: Auto Grouping! Learn more

TDD vs BDD: A Developer’s Pocket Reference With Examples

Today we bring yet another testing-related concept for you. Well, we're bringing two: TDD (Test Driven Development) and BDD(Behavior Driven…

By Erin,

Today we bring yet another testing-related concept for you. Well, we’re bringing two: TDD (Test Driven Development) and BDD(Behavior Driven Development). These are two widely known software development techniques in which automated tests play a central role. But people are often confused with these two concepts. “TDD vs. BDD?” is a question that gets asked a lot.

In today’s post, we’re going to give our contribution to this debate. You’ll understand what TDD is, what its workflow looks like, and you’ll also see a brief example in JavaScript. The same is true for BDD.

After that diversion, we converge, by bringing the two together, summarizing the similarities and differences between them. Let’s get started.

TDD: A Quick Definition

TDD, as we’ve already seen, stands for Test-Driven Development. It’s a software development technique in which we write tests before writing the production code. The tests will, of course, fail since they’re trying to test something that doesn’t exist yet. Then, the developers must write the minimum amount of code necessary to make the tests pass. The idea is that, by strictly following this workflow, the tests will guide the design of the application to a more maintainable state.

The TDD Workflow

Robert C. Martin (aka Uncle Bob) describes TDD using what he calls The Three Laws of TDD:

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

The three simple rules above define the whole workflow of TDD. However, we’re going to explain it in a more streamlined way.

Step #1: Write a Failing Test

The first step in the TDD workflow is to write a unit test for the piece of functionality you’re going to create. The test you’ll write will necessarily be a failing test since you’re trying to test something that doesn’t even exist. In other words, you’re going to be calling classes/methods/functions that you haven’t created yet. This will cause runtime errors when the test is executed. In a compiled language such as C# or Java, the code won’t even compile.

Step #2: Execute All Existing Tests

The next step is to execute all executing tests. This step is crucial because it is essential to ensure all existing tests—if any—are passing. After running the tests, only the test you recently wrote should be failing.

Step #3: Write Production Code to Make the Test Pass

Now it’s time to make your test pass. In this stage, you write the minimum amount of code possible to make the test pass. In other words: you shouldn’t necessarily try to solve the problem at this point. Rather, you should only aim at making the test pass. You’re not only allowed to “cheat”—by returning a hard-coded value, for instance. You’re encouraged to do so.

After writing the production code it’s time to execute the tests again. If your recently written test still doesn’t pass, you have to go back to step #3 and alter the production code in order to make sure it passes.

Step #4: Refactor If Necessary

At last, we get to the final and optional step where you refactor the code in order to remove code duplication and improve the code in general.

A Brief TDD Example in JavaScript

We’re now going to see a quick TDD example, using JavaScript as the language. In our example, we’re going to start solving the String Calculator Kata, developed by Roy Osherov.

Here’s our first test:

The test is super simple. It requires the calculator.js file, which exists, but it’s empty. Then, it verifies whether the add function really returns 0 when we pass an empty string. This test will fail spectacularly since we’re trying to test code that doesn’t exist.

The next step is to make the test pass. At this stage, you don’t need to try to get to the final solution. Instead, do the simplest possible thing for the test to pass. Here’s the code for src/calculator.js:

As you see, we just return 0, and that makes the test pass.

The next phase is the refactor step, which is optional. Here, we do primarily two things:

  • refactoring the code as we see fit (for instance, to remove duplication, to improve readability or efficiency)
  • run the tests again, and they should all pass.

In the example, we don’t have a lot of room for improvement, so no refactoring this time.

BDD: A Quick Definition

With the TDD definition out of the way, it’s now time to define its “cousin,” BDD. Dan North introduced the concept of BDD with an article back in 2006. As you’ve already learned in the intro, BDD is an acronym that stands for Behavior-Driven Development. Based on what you’ve just learned about TDD, you should be able to guess that it’s similar to TDD, but that the development is driven not by tests but by behavior. But what on Earth does “behavior” mean here?

We can think of a behavior as the way the application should…well, behave, to meet some requirements in order to serve a user’s needs.

So, BDD is a sort of extension or evolution of TDD that doesn’t get too bogged down by implementation details and technical matters, focusing instead on higher-level concerns, such as business requirements. BDD is also all about communication. One of its most important and interesting characteristics is that it aims to encourage collaboration between developers, QA professionals, and business analysts, by providing a cohesive, ubiquitous language with it everyone can write and read requirements for the application.

BDD achieves that by using plain-English requirements as a starting point for the tests, allowing and encouraging non-technical participants to collaborate.

BDD Workflow

Let’s look at an example of a BDD workflow.

Step #1: Write the Behavior

The first step is to write the behavior we want to create. Ideally, people from the business—such as the product owner or a client representative, or business analysts—should write the behavior, in English, using the Given/When/Then template (more on that later.)

Step #2: Convert the Plain English Behaviors Into Scripts

The next step is to write programming tests based on the behaviors/requirements written in plain English.

Step #3: Implement the Behavior by Writing Production Code

At this step, we implement the required functionality by writing the production code and then run the behavior to verify whether everything is correct. If it’s not, we change the production code until the behavior tests pass.

Step #4: Refactor If Needed

Then we have the final, optional refactor step, same as with TDD. This stage is an opportunity for tidying up the code, removing duplication, unnecessary complexity, improving readability, and so on.

BDD Example in JavaScript

Time for our BDD example. As we did with the TDD example, we’re going to be walking through the workflow steps,  showing how we’d do them in practice. For the BDD example, we’ll use Cucumber.

The examples we’re going to use will be based on the “10-minute tutorial” you can find on the Cucumber documentation site. Here we go.

Step #1: Write the Behavior

In Cucumber, you describe behaviors using scenarios. Consider the following code:

Here, we define a feature called “Is it Friday yet?” followed with a description. Then we define the scenario using the Given-When-Then syntax. The scenario simply defines that, if it’s Sunday and I ask whether it’s Friday, the answer should be negative.

The next step would be to convert the scenarios written in human-readable English to executable tests. The following excerpt of code shows the codification of the steps of our scenario:

As you can see, we just hardcoded the response “nope” for the “isItFriday” constant. It’s going to make the test/behavior pass, even though it doesn’t fully solve the problem. At this step, the steps should pass.

TDD vs. BDD: All Together Now

We’re now going to summarize the main differences and similarities between the two approaches.

Let’s begin at the start. In TDD, the process starts by writing a failing test case. In BDD, you kick off the process by writing a scenario, in plain, human-readable English.

Both TDD and BDD aren’t testing methodologies—that’s a common misconception. They are software development methodologies that revolve around automated testing.

Both approaches achieve the result of having a comprehensive suite of automated tests covering the application, even though that’s certainly more pronounced with TDD.

Probably the starkest difference between the two techniques is the difference in regards to people producing and consuming the tests. TDD only requires the collaboration of developers. And even if non-technical people wanted to collaborate, they probably couldn’t, since reading TDD generated unit tests require programming knowledge. BDD, on the other hand, encourages the collaboration of not only developers but also QA people, business analysts, and so on.

Finally, the verdict. What is the answer to the “TDD vs. BDD” debate? Is there such a thing as the best approach?

The answer is that there isn’t a one-size-fits-all answer. There are scenarios where TDD is more indicated than BDD and vice-versa.

BDD might be the best approach for applications where the actions are dictated by the user’s behavior. On the other hand, for things like libraries or RESTful APIs, TDD might be the most suitable technique.

Back to You Now

In this post, we’ve examined the “TDD vs. BDD” debate, defining each of the two approaches along with examples. By now, you should have a solid understanding of the fundamentals of both approaches. Now, read more about both techniques and practice.

Don’t forget to stay tuned to this blog, where we constantly publish valuable content related to testing, such as this comprehensive tutorial on Cucumber.

This post was written by Carlos Schults. Carlos is a .NET software developer with experience in both desktop and web development, and he’s now trying his hand at mobile. He has a passion for writing clean and concise code, and he’s interested in practices that help you improve app health, such as code review, automated testing, and continuous build.

Testim's latest articles, right in your inbox.

From our latest feature releases, to the way it impacts the businesses of our clients, follow the evolution of our product

Blog Subscribe