Unit testing Node.JS APIs
Tags: node, testing, javascript, api
Published: 2020-04-18 11:56:36

---
title: Unit testing Node.JS APIs
published: true
description: Introduction to unit testing Node.JS APIs
tags: #node, #testing, #javascript, #API
---

As a professional software developer dedicated to Node.js RESTful APIs, I have come to the following conclusion:

>  Developers are not paid to write code.
They are paid to deliver tech
**solutions**.

And these solutions should be...

* Concrete and robust
* Have high availability no matter the load
* Reliable
* Secure
* Cost-effective
* Maintainable

Developers should also be able to **provide evidence** that their solutions match the criteria mentioned above. They should also be able to **detect and fix** easily and fast any bug or issue that may occur.

And that's where **Unit testing** comes in

# Definition

> Unit Testing is a level of software testing where individual units/ components of a software are tested. The purpose is to validate that each unit of the software performs as designed.
Source: [softwaretestingfundamentals.com](http://softwaretestingfundamentals.com/)

# But which are the units in an API?

The units in an API consist of:

* API requests
  * HTTP method (i.e GET, POST, PUT etc.) API endpoint (i.e /v1/posts)
  * Request parameters
  * Request headers
* Request Body • Models
  * Properties / fields 
  * Model methods

# Learning by example: An example API
For the purposes of this article, we will use an example API for a classic book  Library (yes, the original one where you can borrow books, study, etc.)

The API will be composed of the following elements:

* Entities / Models
 * Books 
 * Users

* Endpoints
 * GET /users 
 * POST /user 
 * GET /books 
 * POST /book

The endpoints have the form shown in the following screenshots:
We use [faker.js](https://www.npmjs.com/package/faker) to generate the dummy data that the API will use.

GET /users endpoint
![GET /users](https://dev-to-uploads.s3.amazonaws.com/i/y3p4so4dnrbahhng4q28.png)

POST /user endpoint
![POST /user](https://dev-to-uploads.s3.amazonaws.com/i/1jv2m2f6p3thqzr3pc9z.png)

GET /books endpoint
![GET /books](https://dev-to-uploads.s3.amazonaws.com/i/mcgu7btsrp160bn4ts5g.png)

POST /book endpoint
![POST /book](https://dev-to-uploads.s3.amazonaws.com/i/14px0kvacvtbxf4yzmg9.png)

So far so good. I think it is crystal what each endpoint does and the form of data that it responds with.

An example response for the GET /users endpoint looks like this:

![Example response](https://dev-to-uploads.s3.amazonaws.com/i/0s8hj3zo4vqcdlb8hi4u.png)

# But what do we really want to test?
By writing unit tests for an API, we try to answer questions like these:

* Does **GET /users** always responds with an **array of user objects**?
* Does **POST /book** always responds with the **book object submitted**?
* Does **POST /user** responds with the right error code when one or more **required fields are missing**?
* Does **POST /user** responds with the right error code when email **does not have the correct format**?

Of course, there are many more questions that we may want to answer to be sure that our API works as expected but for our example, those are some important ones.

# Let’s grab a cup of coffee (or tea ?)

The 2 main libraries we use to write unit tests for Node.JS applications are [Mocha](https://www.npmjs.com/package/mocha) which is the main unit testing framework and [Chai](https://www.npmjs.com/package/chai) which is the assertion library. Chai provides the functions that make the checks we want to perform a lot easier. 

i.e
```Javascript
response.should.be.a('string'); 
response.should.not.have.property(‘phone’);
```
Chai library has 4 main interfaces that do the same thing with
different syntax:
* should 
* assert 
* expect

i.e the following 3 lines perform exactly the same test.

```Javascript
email.should.be.a(‘string’) 
expect(email).to.be.a(‘string’) 
assert.typeOf(email,’string’)
```

# A look in the `package.json` file of our project

In order to run tests with the default `npm test command` we should add the following value in the `scripts` key of our `package.json` file.

```JS
"scripts": {
 "test": "nyc mocha --timeout 10000"
}
```

We set the timeout for each test case (a test case performs an API call) to 10K ms (or 10s).

# The anatomy of a test

![Anatomy of a test](https://dev-to-uploads.s3.amazonaws.com/i/qeq8danptt9wb61s0b1z.png)

As you can see a test is composed of 
* The dependencies (common for many test cases)
* A name and a description
* The API call
* The actual tests (assertions)
* The callback that notifies mocha library that the test has completed.

# Coverage reports and nyc
[nyc](https://www.npmjs.com/package/nyc) is a tool that reports how much of the total code is covered by the tests we have written. It also reports all the uncovered lines so to know where to look and what tests to write.

A coverage report after the completion of the tests looks like this:
![Coverage report](https://dev-to-uploads.s3.amazonaws.com/i/313yrws5zv54hnc6v0le.png)

# Some good practices regarding unit tests

* It is a good practice to **save the different payloads** we use to test POST endpoints **in separate .txt or .json files**.

* We should also create different test declarations for different things /
functions we want to check.

* We should also try to write tests in order to form different “scenarios”. 
i.e The DB is initially empty, so we POST a new user, then the user created POSTs a new book, then we DELETE the book and then the user etc.

* We should also write tests to check **error codes and errors**. Bugs and issues may be hidden in the validation logic.

* We should also write tests checking **access level** if our API has different user types with different access levels

* Finally, we should try to reach the higher coverage we can. However, we should always keep in mind that it is impossible to reach 100%.


# That's all folks!

I hope you enjoyed it and that it will help you to write unit tests for your Node.JS API in the future.