Introduction to Unit Testing with JavaScript and Jest

Ideally testing catches bugs before they are sent to users.

In the previous article, we introduced Testing, today, we'll be talking about Unit Tests.

Unit testing allows you to validate that individual components of your software works as designed.

In this article, we'll learn how you can start testing your JavaScript application components with Jest Testing Framework.

Table of content

  • Planning your unit tests
  • Benefits of Unit Tests
  • What is Jest
  • Writing the tests

Requirements to run examples;

  • NodeJS
  • NPM

Planning Your Unit Tests

Planning is an important part of writing unit tests, you have an idea and you want to start executing. First step is to write the functionalities, the specification for how the application will work — you normally do this with a piece of paper, a card, or whatever tool you desire.

After this step you start designing the functions and classes that will be in your app to make everything come together.

Once you have this on ground and everything looks pretty clear, next step is to write the tests — this style of writing test is know as test driven development.

In Test driven development, you write your tests first before writing the actual code. You can decide to write your test after the code, whatever works for you is fine. Just make sure you cover as many test cases as possible. That's the benefit of planning your tests actually.

For example if our application needs a function that will take a users date of birth and return their current age; like so

./app.js

function getAge(yearOfBirth){

   let currentYear = new Date().getFullYear();

   let age = currentYear - yearOfBirth;

   return age;

}

module.exports = getAge;

Ideally, this function should return your age. And our test should look like this:

./tests/app.test.js

const getAge = require("../getAge.js")

describe("User Test", function(){

   it("should return user's age", ()⇒{

        expect(getAge(1993)).toBe(27)

    } )

})

If you have only this test case, you'll get 100% coverage but that's not the truth. Things can still go wrong. Because you haven't provided a case where the user enters a string instead of number or any unexpected data.

You might be confident that only numbers will come in, well, that might be true if you have validators but how are you sure your validation works as expected.

What if someone enters a negative value? There are a lot that can go wrong, planning your test will allow you figure them out first and fix them in your code.

Testing allows you to get the bigger picture and break it into smaller pieces.

Benefit of Unit Testing

  • Units test increases your confidence to maintain your code. With unit test in place, each time you change something in your code and run your test, you'll catch any error that was introduced as a result of that code change and easily fix it.

  • Unit Testing forces you to write readable and maintainable code. For your code to be testable, it has to be modular and your functions wouldn't be doing too many things at a time. That's part of writing code that is maintainable.

  • Development is faster. It's super frustrating to fill forms. It's even more frustrating filling forms when you are investigating a bug during development as you'll have to fill out that form as many times as possible until that functionality works well. traversing to the browser or postman all the time and clicking around can be a pain. But the joy of running npm test is refreshing. To be honest, writing test can be tedious but the pay-off can compensate for the stress.

  • The cost to fix a bug during unit test compared to when you find those bugs in acceptance test or in production is cheaper.

  • Debugging is easy. Compared to other test levels, when a test fails you know exactly where to look to fix it.

What is Jest

Introduction to unit testing

Jest is a testing framework created by Facebook with focus on simplicity. There are other testing frameworks you can use if you want such as chai, mocha, tapejs, etc. But for this tutorial, we'll be using Jest. Generally tests concepts are the same, just different implementations and features.

Jest has a robust API that is documented properly. We'll be using some of it's API from now on to write our tests. I'll explain them as we proceed. But you can read more about them and the once you want to use at the time. For now, let's get the understanding first.

Writing the tests

You'll notice that we've writing a test before but I didn't explain it, so, here we are going to explain that first test.

const getAge = require("../app.js")

describe("User Test", function(){

   it("should return user's age", ()⇒{

        expect(getAge(1993)).toBe(27)

    } )

})

First of all, we'll need to create a node application, you can use Jest in any JavaScript application, we are going to use a node app. You'll need to have NodeJS installed.

create project directory ⇒ profile

create a file ⇒ app.js

create another directory for the test files ⇒ tests

create a file for the app test ⇒ app.test.js inside the test directory test files should follow this convention. [the file you are testing].[test].[js] so jest knows that that's a test file.

It should look like this

.
├── app.js
└── tests
    └── app.test.js

Now, run npm init to initialize the node app

Next, run;

npm install jest

Next, we'll set up Jest to be our test runner.

Open your package.json file and modify test in the script object to this:

"test": "NODE_ENV=test jest --testTimeout=10000  --detectOpenHandles",

we are setting the environment to be test NODE_ENV=test setting how long it takes for a test to timeout to 10,000 miliseconds and also checking if there are open handles, any asyn code that might stop our test from working properly.

And also add;

  "jest": {
    "testEnvironment": "node",
    "coveragePathIgnorePatterns": [
      "/node_modules/"
    ]
  }

Your package.json file should now look like this:

{
  "nam "profile",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "directories": {
    "test": "tests"
  },
  "scripts": {
    "test": "NODE_ENV=test jest --testTimeout=100000  --detectOpenHandles"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jest": "^26.5.2"
  },
  "jest": {
    "testEnvironment": "node",
    "coveragePathIgnorePatterns": [
      "/node_modules/"
    ]
  }
}

That's it. We are ready to go.

Once Jest is install and setup correctly; it comes with hook functions you might not need to explicitly import them to use them but if you want to import them, you can.

For example; we used the describe and it hook functions in our test but we didn't import it.

const getAge = require("../app.js")

describe("User Test", function(){

   it("should return user's age", ()⇒{

        expect(getAge(1993)).toBe(27)

    } )

})

We use the describe function to create a test suite while the it function is use to create test cases, you can also use the test function as well. Jest provides many easy ways to do things you'll have to look at the documentation for more options.

We use expect to make assertions . We expect this function getAge when pass the parameter 1993 to return 27 as the age of the user.

expect(getAge(1993)).toBe(27)

There is .toEqual, .toBeFalsy(), toBeThruthy() and so on. You can easily find and use the one that fits your assertions in the doc.

run npm test and see your test passing

Passing tests
You can add more test cases to increase the coverage and make your test more powerful.

There is so much you can do with Jest we have just scratched the surface.

You can spend sometime looking at the documentation. It's pretty explanatory.

That's it for now,

Stay safe.


Share.


0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *