An introduction to Test Driven Development in JavaScript

Dillon
JavaScript in Plain English
3 min readJun 23, 2020

--

Photo by Ferenc Almasi on Unsplash

Test Driven Development (TDD) is a widely used term in the developer community, but until you really understand why it’s useful, it can be hard to see the benefit. Simply put, TDD is writing tests to define how your code should work, then writing code to make those tests pass.

This article will go through the basic way to develop using the TDD process by writing a simple function that adds two numbers together.

Note: This article expects you have a basic understanding of Jest.

Setup

We’ll set up a super simple project to get up and running, we won’t do anything fancy.

Start by creating a new directory /tdd-basics .

Install the dependencies

Let’s initialise our new project. I’m using yarn but npm works too!

yarn init

For running tests we’re going to need Jest, a simple JavaScript testing framework. Not too important for this project but Jest should usually be a dev dependency since it’s only needed when developing.

yarn add --dev jest 

Add test script

To run Jest we need to create an script in our package.json

{
...
"scripts": {
"test": "jest"
},
...
}

Create files

For this exercise we need two files, one for our tests and one for our code.

touch sum.js sum.test.js

Writing the tests

Before we can write any tests we need to import the sum function so we can use it.

First test

Our first test will be to check the happy path scenario to make sure the function does what it’s supposed to.

Very simple, we just call the function a few times and make sure the output is what we expect.

Further tests

We can’t just write tests to check the happy path, we need to cover any potential edge cases.

Our sum function should only take two arguments and those arguments should both be integers. We are putting down our requirements of how we expect the function to work in these scenarios into the tests.

If we run the test now you’ll see they all rightfully fail.

FAIL  ./sum.test.js
✕ adds the first number to the second (2 ms)
✕ only adds the first two arguments
✕ non integer args should throw error (17 ms)

Implementing the function

First we need to create the basic function.

Now we can run the tests again.

FAIL  ./sum.test.js
✕ adds the first number to the second (2 ms)
✕ only adds the first two arguments (1 ms)
✕ non integer args should throw error (17 ms)
● adds the first number to the secondTypeError: sum is not a function2 |
3 | test("adds the first number to the second", () => {
> 4 | expect(sum(1, 2)).toBe(3);
| ^
5 | expect(sum(2, 2)).toBe(4);
6 | expect(sum(10, 21)).toBe(31);
7 | });
at Object.<anonymous> (sum.test.js:4:10)

Still all failing! Looks like we forgot to export the function.

If we run the tests now…

FAIL  ./sum.test.js
✓ adds the first number to the second (8 ms)
✓ only adds the first two arguments (1 ms)
✕ non integer args should throw error (7 ms)

That’s a little better… we just need to satisfy the last test case.

We need to throw an error if the arguments aren’t integers. For simplicity we’ll use Lodash. Let’s add it as a dependency.

yarn add lodash

Adding the type check to the code.

We’re just checking if either of the arguments isn’t an integer and throwing a TypeError with a descriptive message.

Let’s run the tests one last time

PASS  ./sum.test.js
✓ adds the first number to the second (10 ms)
✓ only adds the first two arguments (1 ms)
✓ non integer args should throw error (10 ms)

And we’re done! We’ve written a simple function to add two numbers that satisfy our tests.

Conclusion

Test Driven Development isn’t just about writing tests, it’s a way of defining requirements for how some code should work, that you can then lean on as you write your code. This is just a simple example, but you can see how writing the tests before you start coding allows you to catch mistakes and develop quicker.

It also gives you the flexibility to change the implementation quickly without worrying that you’ve broken something.

TDD can seem like extra development work but it pays off in the long run with a reduction of regression defects, reduced developer time and no retroactive test writing.

--

--

Staff Engineer @Wagestream | Building @LclyMe | Geo-data nerd | OpenGraph oeficionado