Improving the testability of software is extremely important, and a difficult ideal in its own right. To achieve that, engineers and others interested in software testability have created many strategies, tools, and methodologies to improve the testability of software solutions.
With so many methodologies and techniques available, which one should you choose? Two of the most prominent methodologies I've encountered are test-driven development (TDD) and behavior-driven development (BDD). In this post, I'll describe what TDD and BDD are, discuss their real-world applications, and explain how they differ. In addition, I'll talk about considerations between TDD vs. BDD.
Here are some facts to consider when thinking about TDD vs. BDD.
What Is TDD?
Test-driven development (TDD) is one of the most popular methodologies today for adding testability to a software project. Test-driven development became popular around 2003 via Kent Beck, alongside the test-first extreme programming principle. TDD aims to provide 100 percent test coverage in code by working with a very short feedback cycle when writing code. The short feedback cycle drives implementation, verifying functionality with automated testing. In other words, you write tests beforehand and then write functionality so that the software passes those tests.
The TDD methodology and its short feedback loop are defined in Kent Beck's book Test-Driven Development: By Example with the following steps:
1. Write a failing test (red).
2. Make the test work ASAP (green).
3. Refactor the code.
Step 1: Write a Failing Test
The first step with TDD is to create a "red" test that fails. This test doesn't need to pass, or even compile at all. The primary purpose of this step is to define the functionality to test.
Step 2: Make the Test Pass ASAP
Once you've established a failing test, the next step is to make it pass as quickly as possible. There are no rules in getting the implementation correct to turn the test "green."
Step 3: Refactor the Code
Once you have a passing test, you have the means to test the functionality created in step two. The next step is to refactor the code to a good standard, such as by removing any duplication created during the previous steps. While refactoring, you'll have the ability to use the test you just created to ensure that the code is always working as intended.
TDD: Benefits and Drawbacks
Now that you know the steps involved in test-driven development, let's look at some of the benefits and drawbacks. Some of the benefits of practicing TDD include:
- Improve code quality by virtue of writing code with testability in mind—this generally results in well-defined and decoupled code that is easy to maintain over time.
- Provide a framework of automated tests that can provide a metric of the code quality at any point. This is great for understanding regression effects when changing functionality in the codebase.
- Test creation alongside functionality creation. Instead of tests being an afterthought, they become as critical as writing functionality.
Of course, there are some disadvantages as well:
- When considering the business case for writing with testability in mind, it can be difficult to explain how testing can contribute to the bottom line. This is especially difficult for teams working under unrealistic deadlines.
- To follow TDD correctly, you need both the knowledge to actually follow the TDD methodology correctly and the discipline to commit to following the rules of the methodology. Especially as timelines tighten and deadlines loom closer, it becomes easy to push off testing as something to "address later."
Now that we've covered the basics of TDD, let's talk about the next testing methodology in our discussion of TDD vs. BDD, behavior-driven development.
What Is BDD?
Behavior-driven development (BDD) combines TDD methodology with core principals from object-oriented programming and domain-driven development. BDD allows both technical and non-technical teams to be involved in software development testing efforts. Writing tests in a way that explicitly defines the behavior expected for the software accomplishes this by allowing both non-technical and technical members to be involved in the test definition process.
Behavior-driven development focuses on creating user stories explaining the desired functionality. This is opposed to test-driven development, which focuses on having a feedback loop driven by written tests. In 2007, Dan North wrote a guideline for the different steps of defining a user story—let's take a look.
Step 1: Given
First, a behavior-driven test will establish the initial context for the test. This step is called "given," which describes a situation in which functionality will be determined. This step is important in establishing the state of the application before testing for functionality. Since a behavior-driven test should still look to isolate functionality, it's important to be specific with the context of the user story when determining functionality in the application.
Step 2: When
The next step in writing a BDD test is to establish the "when" criteria. The "when" step describes the action occurring with the "given" content. Generally, this step is a verb describing something happening in a system, such as clicking a page or registering a user.
Step 3: Then
Finally, the last step is to define a "then" statement for the behavior-driven test. This statement describes the final result that occurs after performing an action with the "when" statement.
BDD: A Quick Example
Let's look at an example. If I'm building an application that collects registrations for an event, I'd think about the different functionalities this application can have. A core function to test would be the capability to add an attendee to an already existing event. My "given" statement would look something like: given that an event already exists and is selected.
Next, I would create a "when" statement to provide an action to perform for this test. Since my goal is to add an attendee to an event, my "when" statement would be: when a user registers for the given event.
Lastly, I would finish the test by including a "then" statement. Once the user registers for an event, I need to confirm the user was actually registered. My statement could look like: then confirm the user is registered for the event.
BDD: Some of the Benefits
Let's go over a few benefits of using behavior-driven development:
- Good user of establishing strong business requirements for the application. Behavior-driven tests provide a framework of tests focusing on the business functionality of the application since they are created with desired behavior in mind.
- High collaboration between domain expert and developers. Building tests in this way helps prevent miscommunication between requirements and implementation.
- Provides repeatable high-level tests for regression throughout the application. If you've ever run into a case where business users forget the functionality they're asking for, this benefit will work really well for you.
Now that we have a better understanding of behavior-driven testing, let's look at the differences between TDD vs. BDD.
TDD vs. BDD: Understanding the Difference
When looking at the difference between TDD vs. BDD, it's important to understand that you don't have to choose just one or the other—you can use TDD and BDD together to cover your organization's testing needs. By using aspects of both TDD and BDD, you'll be able to have low-level tests for the details of the codebase, and higher-level tests that touch on the direct functionality desired by the customer. Additionally, the different sectors of your organization can have different involvement in the testing process. A different workflow in test creation can involve different team members, depending on their technical capability.
First, consider an environment where the development team is driving internal functionality. Test-driven development centers around tests defined by the development team. TDD's short feedback cycle works well within a development team since the tests created with this methodology tend to be small and quick.
Second, an environment with more collaboration between the domain experts and development team will benefit from a stronger behavior-driven development process. This allows for tests written in simple English that makes sense for a non-technical user. In addition, behavior-driven tests make for great acceptance tests. These tests define the desired functionality without considering implementation details, allowing them to include non-technical users in creation.
Using TDD and BDD in Harmony
This post should have given you a good understanding of what test-driven development and behavior-driven development are. When considering whether to implement TDD vs. BDD in your workflow, both can create an effective test creation strategy. If you aren't using one (or both!) of these methodologies, give them each a try and see if they help you with creating better tests for your software.
This post was written by Dave Farinelli. Dave is a senior software engineer with over eight years of experience. His specialty is in providing enterprise-level solutions for healthcare and insurance clients. Dave holds a B.S. in computer engineering from Kettering University in Flint, Michigan.