Both test-driven development (TDD) and behavior-driven development (BDD) are common ways to ensure that testing remains an essential part of the software development cycle.
TDD involves intentionally writing a failing test, writing the minimum amount of application code that allows the test to pass, and running the test again to ensure it passes. BDD uses the same principles as TDD but applies them on a larger scale. BDD involves asking what the purpose of a feature or application is, writing the acceptance criteria, and then writing the code to ensure that the application or feature fulfills those criteria.
This article discusses the similarities and differences between TDD and BDD and which testing strategy you should use depending on your scope.
Before exploring their differences, let's look at what each of these testing strategies entails.
Tests can be written either before or after the application itself. TDD means that software engineering teams prioritize writing tests first. What would that look like?
Imagine that you want a `hello` function that returns the string `hello world`. Using TDD, you would write the test first:
1test('hello', () => {2const result = hello();3expect(result).toBe("hello world");4})
Because the function `hello` does not yet exist, the test automatically fails.
Next, you'd write the minimal amount of code in the application that would allow the test to pass. In this example, you'd write the `hello` function in the application's JavaScript file—something like this.
1const hello = () => {2return "hello world"3}
Once the test passes, you can move on to the next thing you want to build. At times, test-driven development practitioners will also first refactor the code to ensure that it's written with minimal clutter.
Since test-driven development requires you to write tests before writing the functional aspects of an application, it's well-suited for smaller units of code that are loosely coupled.
BDD can be considered an extension of TDD. It applies the principles of TDD at a larger scale by going beyond simply testing functions, code blocks, or services—it brings into question why the application exists in the first place.
BDD is well-suited for tests that require you to look at the big picture of the application. As John Ferguson Smart explains in his book BDD in Action, "BDD practitioners use conversations about concrete examples to build up a common understanding of what features will deliver real value to the organization." In practice, BDD often uses Gherkin language to "[define] scenarios, or concrete examples of how a particular feature or story works." While Gherkin is not a requirement for BDD, it provides a helpful set of keywords to frame the test in a straightforward and readable format.
For example, if you were asked to build an application that reminds its users to meditate every twenty-four hours, you might formulate the acceptance criteria in Gherkin like so:
Feature: Notification system Given the user downloads the application on their phone When 24 hours has passed Then the user will receive a reminder to meditate
Of course, additional steps and hedges may be necessary for more complex scenarios. For example:
Feature: Notification system Given the user downloads the application on their phone And turns on app notifications When 24 hours has passed And the user has not logged their meditation session to the app Then the user will receive a reminder to meditate And the notification will reset
BDD looks at the bigger picture, but that doesn't mean it's better. Both TDD and BDD can bring value to your team.
Even though many parts of BDD and TDD overlap significantly, different scenarios will call for different strategies. Let's consider the main differences between TDD and BDD to determine when each one is more appropriate.
In TDD, participants are usually limited to one or a few engineers at most. TDD, by nature, requires the developer to run the unit test in their own integrated development environment (IDE), see that it fails, write the minimum amount of code for it to pass, and refactor any unnecessary code that may hinder readability or functionality.
This process requires more hands-on knowledge of how a code block is functioning. Though the engineer may bring someone in to watch or pair the program with, following the steps of TDD does not—and should not—require collaboration.
BDD, on the other hand, requires an all-hands-on-deck approach. The product owner, project manager, and other team members are all involved in determining how the application should behave and what the purpose of the feature or application is. For example, they may suggest ideas regarding what the customers want the application to look like or how it should behave given a scenario.
The BDD process is less technical by nature and should encourage team members to discuss whether the functionality is possible or translatable into code before the developer implements what was discussed.
Since TDD begins with writing a test before any business code can be written, developers who follow TDD entirely should have 100 percent code coverage. Testing everything ensures that each block of code fulfills a function in the application, and it provides a strong foundation for understanding the bits and pieces of how the application works.
However, having 100 percent test coverage may sometimes not be necessary. For example, if a function simply returns the same string every time (like the `hello` function above), writing a test for it may not be necessary. Because the function does not reach out to other services or functions and does not have any dependencies, the developer may not want to spend extra time writing an additional test for something already so obvious.
BDD does not worry about test coverage. It simply provides acceptance criteria for how the application should work. The test passes when the application behaves the way it's supposed to, and another story could be created to refactor or change anything that requires attention.
This can often make the developer's job easier, though intentionally leaving areas of the codebase untested may mean the application accrues technical debt. Discerning areas that need refactoring and prioritizing them can be difficult with BDD, as its test criteria simply ask, "Does the feature or application work the way it should?"
Since TDD prioritizes unit tests written in an IDE, tests could be written in virtually any programming language with testing frameworks or built-in testing functionality. For example, Jest, a popular testing framework, is written in JavaScript for testing JavaScript code or JavaScript-based libraries and frameworks like React, Angular, and Vue.
Because unit tests in TDD are written in programming languages, developers are often responsible for the task due to the technical experience required.
As mentioned previously, BDD uses Gherkin as the primary language for writing tests. It's easily adaptable and translatable into virtually any written language since one of its goals is to allow cross-team communication. In fact, Cucumber.io provides guidelines for translating common Gherkin words used to define scenarios for how applications should behave.
Since no knowledge of programming languages is required to write Gherkin, team members with differing levels of technical knowledge can collaborate to write the tests.
TDD requires an IDE, knowledge of programming languages, and, if applicable, knowledge of testing frameworks. Popular testing frameworks like Jest, Selenium, or Mockito can be used, along with IDE extensions like NCrunch and various debuggers.
Jest extension lets tests run automatically when the test file is saved.
Depending on the programming language, framework, and the developer's preferred IDE, tests can be written in a variety of forms and formats.
On the other hand, BDD only requires knowledge of the Gherkin syntax and a shared document for collaboration purposes. However, testing frameworks and tools can aid in the process of creating some of these acceptance criteria and even automate some of the tests.
Tools like Sauce Labs, Cucumber, or JBehave can often allow developers to integrate these tests with their chosen IDE and allow them to translate the given scenarios to their programming language of choice. These tools can provide a smoother transition from idea to execution.
BDD and TDD are both test-based development strategies to define what the application (BDD) or code block (TDD) should do before they are built.
Thoroughly considering their differences allows you to determine which strategy best fits your needs. TDD is well-suited for smaller units of code, while BDD works well for applications that require you to consider the big picture. TDD is often led by a sole developer and is not as collaborative as BDD, which prioritizes cross-team communication. Finally, TDD requires more technical knowledge, while BDD aims to make it easier for less technical team members to be involved.
One of the best ways to perform both TDD and BDD is through Sauce Labs. Its comprehensive test and error monitoring solution allows you to perform cross-platform tests either automatically or manually, along with UI, API, and BDD tests that require little to no code.