Introduction to TDD with JavaScript

David Fellows
4 min readFeb 16, 2020

--

This is my first post in a series that dives into TDD (Test Driven Development). I’m going to cover some of the basics of what it is, the benefits, some of the types of tests it uses, and the framework Jest which you can use to implement it. Testing is a valuable skill for any programmer allows you to create more reliable applications. In future posts I’m going to focus on how to write each type of test that makes up TDD.

So what is TDD?

TDD is an iterative approach. Just like say, a living organism evolves and adapts itself to its environment, so too does code — evolving and adapting itself to its tests. (Arek Torczuk)

TDD is a methodology that involves writing tests that fail before development and then writing new code in order to make those tests pass. Each test specifies and describes what that code will do. If TDD was explicitly followed you would do this for every small function in your program until there was 100% coverage (a lofty goal)! However, the primary aim is to make sure everything is operating as expected, covering all inputs and scenarios. Programmers try and use the least amount of code possible to achieve the expected result and then go back to refactor for elegance and team design specification. This is as opposed to a traditional approach where you write code, see if it works, and then refactor. This diagram illustrates the basic process of TDD:

TDD process, image from testlodge.com

Why do we need TDD and what are the benefits?

Let’s be honest, code is messy. I recently heard that the base code for a single Tesla car is over 600 million lines. As programs grow larger and and code interacts in increasingly complex ways bugs become a likely possibility. Functions become interdependent and errors can occur in areas far from where you are actually working! TDD’s goal is ultimately to make code simpler and bug free.

Proponents of TDD have reported the following benefits:

  • While time consuming at first, TDD in the long run cuts development costs. Healthy code base should be maintained continuously and with tests you can be confident that your functions won’t break. Everything still passing? You’re good to go! If they aren’t you’ll have resources and information to track down the bug.
  • TDD promotes conscious decision making because it forces you to think about what you are trying to accomplish before implementation. No more hacking your way to a solution!
  • TDD creates SOLID code. Simpler code is easier to test, forcing programmers to create more elegant solutions that follows the Single Responsibility Principle.
  • Unit tests are created with descriptions that even non-technical people are able to comprehend. They can act as documentation for the code itself.
  • TDD supports long term scalability and major changes in architecture. Without tests engineers have to add changes without true integration, resulting in problems down the line.
  • TDD prevents scope creep by having clear goals and defined requirements. No more adding “gold plating” or features that don’t contribute to the programs original purpose.

I wanted to conclude by stating that while it is a commonly held belief that TDD overall reduces development costs and time, there is a growing subset of programmers that are arguing against its benefits. In my opinion it’s still a better approach to preventing bugs so your customer doesn’t find them.

Types of tests

Unit tests

Unit tests are the bread and butter of the testing world! They aim to test a fully isolated piece of code like a function by providing input and checking for an expected output. They are the easiest to write and should make up most of your test suite.

Integration tests

Integration tests deal with dependencies such as when a function calls another function. All of your unit tests could be working but your program crashes because they do not work together properly. The more dependencies or server calls involved the harder it is to write. Being skilled in these will make you very valuable as a QA!

End to end tests

E2E tests (also known as functional, application, full flow or user interface tests) are the most difficult and least common of the tests. They are designed to simulate user interaction with a virtual browser that expects outcomes without looking at internal code.

The Jest Framework

There’s no shortage of test frameworks for every language and type of test. Vitali Zaidman made an extremely comprehensive post of JavaScript options in 2019 here. I recommend checking it out if you have time! To set your application up for testing you will need a runner which executes tests. Second, you will need an assertion library to define your tests and logic. There are packages that take care of these individually (Mocha and Chai) but Jest is becoming ubiquitous and does both of these steps in one program. It’s an excellent choice for getting started and is fast to run on large frameworks. One of the creator’ s goals was for it to be zero-configuration so it’s ready to use straight out of the box!

Jest is distributed through node package manager so let’s install it on a project.

Next create a file named util.test.js — Jest watches any file with the word test in the name. Next, going into the package.json file and configure the scripts file to the following:

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

Jest is now ready to go! After writing tests all we need to do is type: “jest — watch” and it will automatically run. Viola! In the next post I’ll cover unit tests, the building block of TDD!

--

--