Show Buttons
Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin
Share On Reddit
Share On Stumbleupon
Contact us
Hide Buttons

Unit test your Nodejs RESTful API using mocha

Its always a good idea to have some quick and sim­ple auto­mated tests in place for your REST api so that you know that you didnt break any­thing that already worked when you add more func­tion­al­ity. For­tu­nately, set­ting up auto­mated tests is not that hard in nodejs. You just gotta know the right libraries to use and how they work together.

And thats exactly what we will set out to achieve in this arti­cle. All the source code for this tuto­r­ial is com­bined with the node starter kit project and can be found on github in the branch rest-api-unit-test

This is what you would be able to do by the time we are done with this article.

Run an npm script exe­cutes mocha tests against your nodejs REST­ful api.

Lets jump in.


Back­ground

For the pur­pose of this arti­cle, I cre­ated tiny REST api for a /api/users. We are sim­ply using an array to store the names of some users. You can replace it with any com­plex logic of your own api that is prob­a­bly deal­ing with a back­end system.

module.exports = function(app, settings){

    var url = require('url'),
        express = require('express'),
        usersRouter = express.Router();

    var users  = [
        {
            name: 'Tim Cook'
        },
        {
            name: 'Jony Ive'
        },
        {
            name: 'Steve Jobs'
        },
    ];

    // Get a list of all the users
    usersRouter.get('/', function(req, res, next){
        res.json(users);
    });

    // Get the user at the index
    usersRouter.get('/:index', function(req, res, next){
        res.json(users[req.params.index]);
    });

    // Create a new user
    usersRouter.post('/', function(req, res, next){
        users.push(req.body);
        res.json(users[users.length - 1]);
    });

    app.use('/api/users', usersRouter);

};

Pack­ages

To pre­pare our project for unit test­ing, we will need to install 4 npm packages.

  1. mocha : The test­ing frame­work we will use.
  2. grunt-mocha-test : The task run­ner to help us setup mocha.
  3. chai : The asser­tion library that we will use within our mocha tests.
  4. supertest : A library that lets you fake requests to test your REST api’s.
npm install mocha grunt-mocha-test chai supertest --save-dev

Con­fig­u­ra­tion

package.json
Cre­ate a script in your package.json as follows

scripts:{
    // other scripts
    // ...
    "tests-unit": "grunt mochaTest"
}

As you see, we just cre­ated an npm script as an alias for the grunt mochaT­est com­mand. You may already have many other scripts con­fig­ured. For exam­ple, take a look at some of the other scripts that I have setup in my package.json and see if you find any of them to be useful.

Now lets add the mochaT­est grunt task to our Grunt­file. As usual, I will be fol­low­ing a lean Grunt­file strat­egy by keep­ing the task con­fig­u­ra­tions in their own mod­ule under a direc­tory that I call ‘grunt’ and then requir­ing them from my Grunt­file. Below is how my Grunt­file would look like if mochaT­est was the only task con­fig­ured. Look at my grunt­file to see how I have con­fig­ured other tasks which fol­low the same pattern.

Gruntfile.js

module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json')
    });

    grunt.config( 'mochaTest', require('./grunt/mochaTest.js') );

    grunt.loadNpmTasks('grunt-mocha-test');
}

mochaT­est task configuration

Now, lets con­fig­ure our mochaT­est task in grunt/mochaTest.js.

module.exports = {
  all: {
    options: {
      reporter: 'list'
    },
    src: ['tests/unit/**/*.test.js']
  }
};

You can see that we spec­i­fied a reporter para­me­ter that deter­mines the out­put for­mat of the con­sole when we run the tests. Mocha has many other for­mats. I pre­ferred to go with the ‘list’ reporter for­mat for this project.

The other impor­tant para­me­ter is ‘src’, that as the name sug­gests is an array of the url pat­terns for the source files that will be tested. We will keep all of our test files in the tests/unit direc­tory and give it an exten­sion of ‘.test.js’ so that even if the core names of the test files are same as any other file, open­ing them in an edi­tor does not cause any confusion.

That is all that you require for set­ting up the com­mand to run our test. The next impor­tant thing to do is to write the test file itself.


The Test

There are cou­ple of things that we will need to do in our test file.
We need to require supertest to cre­ate a request object and require chai as our asser­tion library.

var request = require('supertest'),
    expect = require("chai").expect;

The request object that we just cre­ated allows us to cre­ate HTTP requests if we do one other thing — we have to cre­ate an app, aka — an instance of express and pass it to the request object. We will need to cre­ate this object almost exactly the way we do it in our app.js file. The only dif­fer­ence being that we dont need to require http, start the server or spec­ify a port.

var express = require('express'),
    ROOT_DIR = __dirname + '/../..',
    config = require(ROOT_DIR + '/config'),
    bodyParser = require('body-parser'),
    methodOverride = require('method-override'),
    cookieParser = require('cookie-parser'),
    session = require('express-session'),
    app = express();

var settings = {
        config: config
    };

// all environments
app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(cookieParser());
app.use(session({
    secret: config.SESSION_SECRET , 
    saveUninitialized: true,
    resave: true 
}));

//This allows you to require files relative to the root in any file
requireFromRoot = (function(root) {
    return function(resource) {
        return require(root+"/"+resource);
    }
})(ROOT_DIR);

We need to do this because we want our app to work just like our real appli­ca­tion, the only dif­fer­ence being that its not a server.

With the app object setup, we can now pro­ceed with writ­ing our mocha tests.

In the mocha tests that fol­low, we do a cou­ple of ini­tial­iza­tion tasks work before we invoke our REST api for testing.

  • We save a ref­er­ence to the console.log. We do this because in my routes, I print log­ging state­ments to the con­sole which will ruin the for­mat of my mocha tests. So we save a ref­er­ence to the log object and before each test exe­cutes, we will set it to an empty function(in the beforeEach func­tion which runs before each ‘it’ block).
  • In the before function(which runs once at the begin­ning of the describe block) we require the route we intend to test in the test cases of this describe block.
  • In each test case, when we are ready to use our asser­tions, we again ref­er­ence the console.log to the pre­vi­ously saved log variable.

The code that you see below has exam­ples of test­ing your REST­ful api using GET and POST.

describe('#/api/users', function(){

    var log = console.log;

    before(function(done){
        require(ROOT_DIR + '/routes/users')(app, settings);
        done();
    });

    beforeEach(function(){

        // Done to prevent any server side console logs from the routes
    // to appear on the console when running tests
        console.log=function(){};

    });

  it('- should GET users', function(done){
    request(app)
      .get('/api/users')
      .end(function(err, res){
        // Enable the console log to print the assertion output
        console.log = log;
        var data = JSON.parse(res.text);
        expect(err).to.be.null;
                expect(data.length).to.equal(3);
        done();
      });
  });

  it('- should GET a user at index (1)', function(done){
    request(app)
      .get('/api/users/1')
      .end(function(err, res){
        // Enable the console log
        console.log = log;
        var data = JSON.parse(res.text);
        expect(err).to.be.null;
                expect(data.name).to.equal('Jony Ive');
        done();
      });
  });

  it('- should POST a user and get back a response', function(done){
    var user = {
        name: 'Steve Wozniak'
    };

    request(app)
      .post('/api/users')
      .send(user)
      .end(function(err, res){
        // Enable the console log
        console.log = log;
        var data = JSON.parse(res.text);
        expect(err).to.be.null;
        expect(data.name).to.equal(user.name);
        done();
      });
  });

});

You can look at the com­plete test file here.

Now when you run npm run test-unit from the ter­mi­nal, you should see your tests pass if every­thing went well.

Also, take a look at the github repos of supertest, chai bdd expect/should and the mocha web­site for any more con­fig­u­ra­tions options, but I hope that what we have here should give you a good base to start from.


Ryan Sukale

Ryan is a UX engineer living in San Francisco, California.

You may also like...

  • Chris Lajoie

    There seems to be some­thing wrong with what­ever is attempt­ing to style the js code blocks.

    • tuto­ri­al­hori­zon

      oh wow, it really does look weird. Thanks for point­ing it out. I will move it all to a gist and update the post.

  • http://www.endivesoftware.com/ Chi­rag Agrawal

    Thanks for point­ing it out.