Table of contents
1.
Introduction
2.
Test-Driven Development
2.1.
The Process
2.2.
Key Benefits
2.2.1.
Example:
2.2.2.
Program:
2.2.3.
Program:
2.2.4.
Output:
3.
Behavior-Driven Development
3.1.
The Process
3.2.
Key Benefits
3.2.1.
Example:
3.2.2.
Program:
3.2.3.
Program:
3.2.4.
Program:
3.2.5.
Output:
4.
TDD vs. BDD
4.1.
What are you Testing?
4.2.
How you’re Testing?
4.3.
Implementation
5.
FAQs
6.
Key Takeaways
Last Updated: Mar 27, 2024

Test-Driven Development and Behavior-Driven Development in Jest

Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Test-Driven Development(TDD) and Behavior-Driven Development(BDD) are prevalent development techniques in the programming world. While performing unit tests, one must know about both of these concepts, understand the differences, and know the functionality of TDD and BDD.

In this article, you will learn about TDD and BDD as development techniques and understand its implementation in Jest through test() and it(). If you are unfamiliar with the Jest framework or writing a Unit test on Jest, we strongly recommend that you check out our Getting Started with Jest and Writing First Unit Test on Jest articles.

Test-Driven Development

Test-Driven Development(TDD) is an iterative approach combining programming, creating unit tests, and refactoring. In simple terms, TDD is a software development practice focusing on creating unit test cases before developing the actual code. The test process drives software development in TDD as the name suggests. 

TDD is a structuring practice enabling developers and testers to obtain optimized code that proves to be resilient in the long term. Here, developers create small test cases for every feature based on their initial understanding. The primary purpose of this technique is to modify or write new code only if the tests fail, preventing duplication of test scripts.

The Process

The process of Test-Driven Development can boil down to three major phases. Different implementations of TDD work on these three phases at the core.

  • Firstly, Developers need to create precise unit tests that verify the functionality of specific features. The test needs to execute, so they must ensure that it compiles. In most cases, the test is going to fail. That is a meaningful failure, though, as developers create compact tests based on their assumptions of how the feature will behave.
  • After the test fails, developers can make the minimal changes required to correct the code, and when re-executed, the test runs successfully.
  • Once the test runs successfully, they check for redundancy or code optimizations to enhance the overall performance. It ensures that they do not affect the external behavior of the program by the code refactor.

Key Benefits

  • TDD Promotes better program design and higher code quality.
  • TDD Reduces project development time.
  • Provides scope for detailed project documentation
  • TDD leads to the development of a flexible and easy codebase to maintain.
  • TDD fosters more accessible addition and testing of new functionalities at later stages of development.

Example:

There are essentially two ways to run tests in jest: test () and it(). According to the official documentation of Jest, it(name, fn, timeout) is an alias for test(name, fn, timeout). Both these methods work in essentially the same way.

The elementary test suite can help explain TDD a little bit, but remember that the actual implementation of TDD is on more significant projects.

Program:

//sum.test.js
//import sum
const { sum } = require("./sum");
describe("Addition of Two Number functionality test", () => {
  test("Add 1 + 2 should be 3", () => {
     expect(sum(1, 2)).toBe(3);
  });
  test("it should fail if string as parameter", () => {
     expect(sum("Hello", "World")).toEqual(
        Error("Expecting number type as parameter")
     );
  });
});
You can also try this code with Online Java Compiler
Run Code

Now that we have the test, we can create the file that creates the function in the root function.  

Program:

//sum.js
const sum = (a, b) => {
  if (typeof a !== "number" || typeof b !== "number")
     return Error("Expecting number type as parameter");
  return a + b;
};
module.exports = { sum };
You can also try this code with Online Java Compiler
Run Code

Output:

Behavior-Driven Development

While most developers are familiar with Test-Driven development, the concept of Behavior-Driven Development(BDD) is not as popular. BDD focuses on the business behaviors your code is implementing. It works on the 'why' behind the code in simple terms and supports a team-centric and cross-functional workflow.

The focus on behavior during development makes the test useful as not just your code is correct but verification that you're building the convenient feature.

The Process

The process of BDD is quite intuitive and straightforward as compared to TDD. There are only two primary phases of development in BDD.

  • The business side of the project specifies the behaviors they want to see in the system.
  • The Developer writes tests asking questions based on their understanding of the system while also writing other behaviors required from a development perspective.

The business and Developer side can refer to the list of system behaviors to see if the new feature will break existing features.

Key Benefits

  • BDD provides strong collaboration thanks to the shared language, product owners, developers, and testers, all having in-depth visibility of the project's progression.
  • Being a non-technical process, BDD has high visibility and can reach a much wider audience.
  • BDD methodology focuses on user needs and meets user needs through software development.
  • BDD can trace each development back to the actual business objectives. That helps in meeting the business needs.
  • BDD allows you to make quick iterations and respond quickly to any feedback from your users so you can make improvements to meet their needs.

Example:

To perform BDD, we will work with jest cucumber. Cucumber is a tool that supports BDD. Cucumber reads executable specifications in plain text and validates the software does what those specifications say. 

Cucumber follows some basic syntax rules, called Gherkin.

Firstly we will do a module called sum.ts, which sums two numbers.

Program:

export default (a: number, b: number) => a + b;
You can also try this code with Online Java Compiler
Run Code

Now BDD requires a feature set. We will approach BDD using a feature called sum_a_pair.feature. We will use Gherkin syntax to write the feature as follows: 

Program:

Feature: Sum a Pair
  It sums a pair of numbers
 
  Scenario: adds 1 + 2 to equal 3
    Given 1
    When add 2
    Then the sum is 3

We can now write our test file (sum_a_pair.steps.test.ts). 

Program:

import { defineFeature, loadFeature } from "jest-cucumber";
import sum from "./sum";

const feature = loadFeature("./sum_a_pair.feature");

defineFeature(feature, (test) => {
  test("adds 1 + 2 to equal 3", ({ given, when, then }) => {
     let x: number;
     let z: number;

     given("1", () => {
        x = 1;
     });

     when("add 2", () => {
        z = sum(x, 2);
     });

     then("the sum is 3", () => {
        expect(z).toBe(3);
     });
  });
});
You can also try this code with Online Java Compiler
Run Code

Output:

TDD vs. BDD

In order to differentiate between the two, we have to consider some factors. Those factors are explained below.

What are you Testing?

BDD focuses on testing smaller pieces of functionality in isolation, while BDD tests an application's behavior from the end user's standpoint.

How you’re Testing?

A single developer can do TDD without any external input from other departments. In contrast, BDD involves managers, developers, and engineers collaborating to develop concrete examples of desirable functionality. There is a lot of communication before implementation.

Implementation

TDD primarily involves writing a test case that fails as the specified function doesn't exist, and after that, we update the code which makes the test case pass, and as a result, we get the feature implemented in the system. On the other hand, BDD creates an executable specification that fails because the respective feature does not exist. We write a simple code that can make the specification pass, and we get the required behavior implemented in the system as a result.

The starting point in a TDD is a test, whereas a scenario is the starting point in a BDD.

FAQs

  1. Which is better, TDD or BDD?
    The best practice is to implement both approaches nicely as they complement each other. BDD uses behavioral tests to guide teams and build products that deliver exact value to the customer while preventing unnecessary code in the development. Combined with TDD, unit testing will improve the quality of the product because we can spot the bugs and fix them sooner, without waiting for them to blow up later after already building more layers in the architecture.
     
  2. When should you not use TDD?
    In TDD, the test code requires maintenance and the production code. So too much TDD makes code more complicated than necessary. Thus the cost of implementing functionality should be kept in mind.
     
  3. Where should you not use BDD?
    BDD requires a dedicated team of developers to work with the client. Communications between the user and the Developer are also essential in BDD, so if the user is not available, it won't be easy to work past ambiguities and questions generated by the user stories.
     
  4. Which is better, TestNG or Cucumber?
    TestNG and Cucumber have entirely different functionalities. Cucumber is a tool supporting behavior-Driven Development. On the other hand, TestNG is defined as "A testing framework inspired from JUnit and NUnit."

Key Takeaways

We have learned two fundamental and essential Development techniques in project development through this article. Both TDD and BDD have their advantages and functionalities. You may need to work with either of them or both based on the project requirements and structure.

With the help of two very similar examples, we have also seen how the implementation varies for TDD and BDD and how we can perform both on the Jest framework. A solid understanding of the concepts of TDD and BDD and the differences between the two can go a long way while performing unit testing. 

We have only just begun our journey to understanding unit testing, so make sure to check out related articles like Setup and Scope for test in jest and Mocking in Jest.

There is a lot more to learn. So head over to our practice platform Coding Ninjas Studio to practice top problems, attempt mock tests, read interview experiences, and much more. Till then, Happy Learning!

Live masterclass