Frameworks that are required to test a nodeJs application:

  • Mocha
  • Chai
  • Supertest
  • Sinon
  • Nock
  • Rewire
  • Istanbul

Mocha is used to unit test nodeJS applications. This blog covers a step by step procedure to unit test any node application. To know the efficiency of unit testing we must know the code coverage of the tests that we are writing. There are multiple tools to do this like Wallaby.js, blanket. js, istanbul. We will be using Istanbul.

To start with unit testing, we must have NodeJs installed in our system and the path set. This is assumed to be already done as we have a node application running on our system. We have to install mocha and istanbul globally to begin unit testing.

To install mocha, type the command : npm install -g mocha

To install istanbul, type the command : npm install -g istanbul

Unit testing is checking the functionality of the smallest piece of code – mostly a function. However that is in the front end javascript code. For backend Nodejs applications created using expressJS, the routes can be tested and the functionality of the files in src folder(all other js files) can be tested.

But before that, lets install a few more dependencies, so that we will install all the dependencies that are required to unit test most of the nodeJs applications.

To install chai – npm install chai –save-dev

To install supertest – npm install supertest –save-dev

To install sinon – npm install sinon –save-dev

To install nock – npm install nock –save-dev

Chai is used to make assertions. Supertest is used to make HTTP assertions. Sinon is used to control the flow in a function and to validate callbacks. Nock is used to create fake servers and return responses when the request hits the fake server. We will be covering all these below.

First, create a folder called test in your application root directory. This folder will contain all the tests that we write for our application. To run these tests, open terminal and navigate to our application’s main directory and type the command mocha.

Create a new test file in the test folder. Its a good convention to create a separate test file for each js file that we are going to unit test. Have a naming convention for our spec files would be great. I follow the fileName_spec.js (*_spec.js) as my naming convention. This can be used to select all spec files at once. If the file that you are going to test is add.js, then name the test file as add_spec.js.

In the spec file first require the modules that are used.

You must start your test case with a describe block. The syntax is

describe(‘ tests the add file’ , function() {

}

Every describe block will have it block. Each it block is a test case.

For example if our add.js is

so in our describe block we add an it suite.

In our terminal navigate to the main app directory and type mocha, to run the spec files. This will execute the tests and return 1 test passing.

This is just a small example as what can be done using mocha. To learn more about this refer https://mochajs.org/. To know about the code coverage run the command istanbul cover _mocha. This will create the coverage report which is a html file and lcov file in a new folder called coverage. The index.html will have the coverage report. Viewing it in a browser would show the coverage and clicking on the file name/ folder name will open the coverage of the specific file and also show the lines that are uncovered with red.

An example for this would be if we just change our add.js file to the following code:

Now just writing a test case to add 5&3 is not enough. The result that we get when we call add(3,2) and add (2,2) will be different. So there are two cases that we must write.

The point to note is just writing a test case to invoke a function is not enough to test a function. Every function has to be tested. If we do not write the second test case, istanbul would show the second if condition highlighted in red. So whenever we see a function or a line of code highlighted in red, we must write a test case to accomodate that scenario too. Thats how we can bring the code coverage to 100%. This is the basic knowhow that is required to test a file in the src folder (contains the server side javascript logic files) of our express app.

So any file in the src folder can be tested in the above fashion.

The next thing to test is routes. To test routes, we use supertest and nock. Supertest is used to facilitate http assertions and nock is used to create a fake server to respond with when making a http call to an external server.

The first things to make is to require supertest and nock in our spec file.

var supertest = require(‘supertest’),

nock = require(‘nock’);

We must also require the app file (if required) and the file to be tested in out spec file. If we do not require the file to be tested, but request only the app file. Istanbul would not calculate the coverage that is produced with our test cases. The file to be tested should always be included in the spec file.

Create a server in the spec file using the below line of code:

server = supertest(app)

where app is the app file (require(‘app’)).

So the code to test a route will be like this:

Instead of post we can use any REST calls like get or put or delete. The set is used to set headers and send is used to send any params to the url in the post request. The expect is what we expect the request status to be like 200 or 301 or 404. And finally the end function is where we get the result the route gives us. With the response that we get we can unit test to validate whether the route works properly.

Testing routes is not similar to testing functions. To test a route we make a call to the route and validate the response that is provided. Usually calling a route would usually cover all the code that is present under that route. The response given by a route would also depend upon the params that we pass. So testing the routes with all different params and then running istanbul would show us if we have missed any scenario. If we find that being the case, then we must write more scenarios to cover all the lines highlighted in red.

Sometimes we find that our code makes a call to an external server. For example our route may be fetching feeds using the twitter api. So our route depends on the twitter api. So to test this route we make a call to the route and this in turn would make a call to the twitter api. The twitter api would fetch the feed accordingly and give a response and this reponse would be returned by our route.

However there comes a question. What if we do not have an internet connection? This would mean that the twitter api would not be able to reach the twitter server and so it would respond with an error and our test case would fail if we do not have an internet connection. This is not acceptable as the tests would give different results based on whether the system is connected to the internet or not.

To overcome this problem, we must always mock any outer URL dependencies. This is done using nock.

If we want to post to twitter api (just an example)

Now if in our code we make a call to twitter.com to the url /posts with params {msg: ‘i love javascript’}, then the call would not reach the original twitter server, but would be handled by our mock server created using nock. For the above nock to work ,the post url and the post param must be the same that is specified in the nock.

Every nock can be used only once. So if we make multiple calls to the server then multiple nocks have to be created. The important thing to note is to add an after block in our main describe block that clears all the nocks. This is a must and if not added then all the requests to the corresponding server would fail.

One more problem that developers normally face when unit testing is finding that our code to be tested depends on an external function / module. In this case we depend upon the external code for our code to run. These external codes must be made to behave the way we want for our code to function properly. We use sinon.js to accomplish this.

Sinon provides two tools which we can use to know/ control the behavior of any code. They are spies and stubs. A spy is used to spy on a function ( as the name suggests!). So for example if we want to know if a particular function was called using some parameters or whether a callback is called, then we use spies.

So if in our file we have a callback function being called

Now we would want to know if the callback is called or not. We can use spies to check if the callback is invoked or not and if it is invoked, then we can check if it is invoked with the expected parameters.

To do it, we first require sinon in our spec file

In our describe block, we add a beforeEach

And in our testcases we call dosomething with callback

Now we know that our code worked properly as the callback is invoked.

The other tool that needs to be learnt is sinon stubs. Stubs are used to mostly make a function behave the way we want. For example if our dosomething function depends on another functions result, but the other function works with live production data, then we use sinon stub. We just stub the other function to yield the result that we want.

This is a common pattern that we see in many functions. To test dosomething we want dosomethingelse.returnVal to return a value. We normally use sinon stubs to do that. We stub returnVal and make it yield the value we want. So dosomethingelse.returnVal would not be called but only the result of the call will be assigned to valReturned.

So whenever dosomethingelse.returnVal is called it returns 3. We can use sinon stubs to control the flow of any functions.

The final problem that one needs to know to solve is to replace variables in our javascript.

//filename: mapFile.js

Now analysing the flow of the funtion loopAdd we find that it takes data and modifies the elements. However we find that we do not need bigArr to contain 2500 elements for validating loopAdd. Even if it had 2 elements we can test the function. So how can we replace bigArr with a dataset of smaller elements?

This can be done using rewire. Install rewire locally using the command:

npm install –save-dev rewire

Then require rewire in our spec file

var rewire = require(‘rewire’);

Now the way rewire works is instead of require(‘mapFile’), we use rewire(‘mapFile’). This would give us getter and setter functions to every variable in mapFile

In our it block we add a beforeEach function

Now the value of bigArr in mapFile is set to bigArr that we defined in the spec file. Similarly any object or function or module can be replaced with anything else using rewire.

SUMMARY:

  • Use mocha to test javascript code. Invoke the command mocha to start the tests.
  • Use chai for assertions.
  • If we find any problematic code then use sinon to spy or stub them to see/ control the behaviour of the functions.
  • Use nock to mock servers to prevent making any http calls to the outside environment.
  • Use rewire to set/ get variables/external dependencies in the javascript file.
  • Use istanbul to calculate the code coverage done by these unit tests.

References :