top

Unit Testing Using Mocha and Chai

Mocha is a testing framework for NodeJs, which simplifies asynchronous testing. Mocha tests run serially.Chai is a BDD / TDD assertion library for node and the browser that can be paired with any JS testing framework.This article aims at providing a basic understanding of running mocha/chai on Node JS Apps, writing tests using Mocha, and setting up unit testing using Mocha and Chai. We’ll be testing a simple user application, using Mocha and Chai.My assumption is that the user has a basic understanding of NodeJs.Requirements- Node installed(At least v6 and above)- MongoDB installed- Text editorThe application source code can be found in here.The Application Structurepackage.jsonIn the root of your project, run npm init to create a package.json file. Update the file with the following contents:{   "name": "mocha-test",   "version": "1.0.0",   "description": "Mocha testing article",   "main": "index.js",   "scripts": {     "start": "node index.js",     "test": "mocha"   },   "author": "Collins",   "license": "ISC",   "dependencies": {     "body-parser": "^1.15.1",     "config": "^1.20.1",     "express": "^4.13.4",     "mongoose": "^4.4.15",     "morgan": "^1.7.0"   },   "devDependencies": {     "chai": "^3.5.0",     "chai-http": "^2.0.1",     "mocha": "^2.4.5"   } }ControllersThis folder contains a user.js file which houses various functions of the application. Update the file with the following contents:let mongoose = require('mongoose'); let User = require('../models/user'); function createUser(req, res) { var newUser = new User(req.body); newUser.save((err,user) => { if(err) { res.send(err); } else { res.json({message: "User successfully created", user }); } }); } function getUsers(req, res) { let query = User.find({}); query.exec((err, users) => { if(err) res.send(err); res.json(users); }); } function updateUser(req, res) { User.findById({_id: req.params.id}, (err, user) => { if(err) res.send(err); Object.assign(user, req.body).save((err, user) => { if(err) res.send(err); res.json({ message: 'User updated', user }); }); }); } function deleteUser(req, res) { User.remove({_id : req.params.id}, (err, result) => { res.json({ message: "User deleted", result }); }); } module.exports = { getUsers, createUser, deleteUser, updateUser };index.jsThis file houses all the server configuration. Fill the file with the following:let express = require('express'); let app = express(); let mongoose = require('mongoose'); let morgan = require('morgan'); let bodyParser = require('body-parser'); let port = 5000; let user = require('./controllers/user');       mongoose.connect("127.0.0.1:27017");                                       app.use(bodyParser.json());                                     app.use(bodyParser.urlencoded({extended: true}));               app.use(bodyParser.text());                                     app.use(bodyParser.json({ type: 'application/json'}));   app.get("/", (req, res) => res.json({message: "User management app"})); app.route("/user") .get(user.getUsers) .post(user.createUser); app.route("/user/:id") .delete(user.deleteUser) .put(user.updateUser); app.listen(port); module.exports = app; ModelsNext, we are going to create models for our application. Create a folder called models and inside this folder, create a file named user.js. Fill the file with the contents below:let mongoose = require('mongoose'); let Schema = mongoose.Schema; let UserSchema = new Schema(   {     firstName: { type: String, required: true },     lastName: { type: String, required: true },     emailAddress: { type: String, required: true },     username: { type: String, required: true},     password: { type: String, required: true },       },   {     versionKey: false   } ); module.exports = mongoose.model('user', UserSchema);It is time to run our application. First off, install the required packages, i.e npm install, then run the application, npm start. You can browse the app on port 5000 using Postman. For example:CREATE:READ UPDATE The above tests may fool you that the app is 100% functional, without flaws. This is not the case. We should write tests to prove that our app is functioning as expected.TestsMocha by default expect a folder called test. Let’s create the folder, and inside this folder, create a test file called user.js . Populate the file with the following contents:As you are familiar with JS, in the above code block, I’m just importing the required packages and files, for our tests to run successfully. Next, create the parent block for the tests:We want the db to be cleared before each test is executed. Mocha has what we call beforeEach . This runs a block of code before each test in a describe. Next, let’s add a test which is going to test the creation of a user: The code block above, first ensures that a user cannot be created without an E-mail address. It also proves that actually when valid data is posted to the /user endpoint, a user is created successfully. Let’s test this. Run npm test. The result should be as follows:A complete user.js test file, which has tests addressing, CREATE, READ, UPDATE AND DELETE, is as shown below. The code is self-explanatory. Copy the code and update the test file that you have so far.let mongoose = require("mongoose"); let User = require('../models/user'); let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../index'); let should = chai.should(); chai.use(chaiHttp); describe('Users', () => { beforeEach((done) => { User.remove({}, (err) => {    done();   });     });       describe('/POST user', () => {         it('it should not create a user without email address', (done) => {             let user = {                 firstName: "John",                 lastName: "Doe",               username: "user",               password: "pass"             }               chai.request(server)               .post('/user')               .send(user)               .end((err, res) => {                     res.should.have.status(200);                     res.body.should.be.a('object');                     res.body.should.have.property('errors');                     res.body.errors.emailAddress.should.have.property('kind').eql('required');                 done();               });         });                 it('it should create a user ', (done) => {           let user = {               firstName: "John",               lastName: "Doe",               emailAddress: "doe@email.com",               username: "me",               password: "pass"           }               chai.request(server)               .post('/user')               .send(user)               .end((err, res) => {                     res.should.have.status(200);                     res.body.should.be.a('object');                     res.body.should.have.property('message').eql('User successfully created');                     res.body.user.should.have.property('firstName');                     res.body.user.should.have.property('lastName');                     res.body.user.should.have.property('emailAddress');                     res.body.user.should.have.property('username');                 done();               });         });     });   describe('/GET user', () => {   it('it should GET all the users', (done) => { chai.request(server)     .get('/user')     .end((err, res) => {   res.should.have.status(200);   res.body.should.be.a('array');   res.body.length.should.be.eql(0);       done();     });   });   });   describe('/PUT/:id user', () => {   it('it should update a user given an id', (done) => {   let user = new User({firstName: "John", lastName: "Doe", emailAddress: "doe@email.com", username: "user", password: "pass"})   user.save((err, user) => { chai.request(server)     .put('/user/' + user.id)     .send({firstName: "John", lastName: "Doe", emailAddress: "john@email.com", username: "user", password: "pass"})     .end((err, res) => {   res.should.have.status(200);   res.body.should.be.a('object');   res.body.should.have.property('message').eql('User updated');   res.body.user.should.have.property('emailAddress').eql("john@email.com");       done();     });   });   });   });   describe('/DELETE/:id user', () => {   it('it should delete a user given an id', (done) => {   let user = new User({firstName: "John", lastName: "Doe", emailAddress: "doe@email.com", username: "user", password: "pass"})   user.save((err, user) => { chai.request(server)     .delete('/user/' + user.id)     .end((err, res) => {   res.should.have.status(200);   res.body.should.be.a('object');   res.body.should.have.property('message').eql('User deleted');       done();     });   });   });   }); }); Running the tests, you should have something similar to:ConclusionIf you’ve keenly followed the above steps from installing Mocha and Chai on Node JS to testing Node JS code with Mocha and Chai, you should be having a functional app with passing tests.This tutorial doesn’t exhaustively cover Mocha testing. There are other concepts which I haven’t illustrated here. For a deeper understanding, you can head on to the docs.Please don’t confuse the above with TDD. After understanding how to test an application, we can build an application using principles of TDD. Hopeful, that’s my next tutorial. Stay tuned! 
Rated 4.5/5 based on 11 customer reviews
Normal Mode Dark Mode

Unit Testing Using Mocha and Chai

Delan collins
Blog
26th Oct, 2018
Unit Testing Using Mocha and Chai

Mocha is a testing framework for NodeJs, which simplifies asynchronous testing. Mocha tests run serially.

Chai is a BDD / TDD assertion library for node and the browser that can be paired with any JS testing framework.

This article aims at providing a basic understanding of running mocha/chai on Node JS Apps, writing tests using Mocha, and setting up unit testing using Mocha and Chai. We’ll be testing a simple user application, using Mocha and Chai.

My assumption is that the user has a basic understanding of NodeJs.

Requirements

- Node installed(At least v6 and above)

- MongoDB installed

- Text editor

The application source code can be found in here.

The Application Structure

Application Structure


package.json

In the root of your project, run npm init to create a package.json file. Update the file with the following contents:

{
  "name": "mocha-test",
  "version": "1.0.0",
  "description": "Mocha testing article",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "mocha"
  },
  "author": "Collins",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.15.1",
    "config": "^1.20.1",
    "express": "^4.13.4",
    "mongoose": "^4.4.15",
    "morgan": "^1.7.0"
  },
  "devDependencies": {
    "chai": "^3.5.0",
    "chai-http": "^2.0.1",
    "mocha": "^2.4.5"
  }
}


Controllers

This folder contains a user.js file which houses various functions of the application. Update the file with the following contents:

let mongoose = require('mongoose');
let User = require('../models/user');

function createUser(req, res) {
var newUser = new User(req.body);
newUser.save((err,user) => {
if(err) {
res.send(err);
}
else {
res.json({message: "User successfully created", user });
}
});
}

function getUsers(req, res) {
let query = User.find({});
query.exec((err, users) => {
if(err) res.send(err);
res.json(users);
});
}

function updateUser(req, res) {
User.findById({_id: req.params.id}, (err, user) => {
if(err) res.send(err);
Object.assign(user, req.body).save((err, user) => {
if(err) res.send(err);
res.json({ message: 'User updated', user });
});
});
}

function deleteUser(req, res) {
User.remove({_id : req.params.id}, (err, result) => {
res.json({ message: "User deleted", result });
});
}

module.exports = { getUsers, createUser, deleteUser, updateUser };

index.js

This file houses all the server configuration. Fill the file with the following:

let express = require('express');
let app = express();
let mongoose = require('mongoose');
let morgan = require('morgan');
let bodyParser = require('body-parser');
let port = 5000;
let user = require('./controllers/user');
     
mongoose.connect("127.0.0.1:27017");
                                     
app.use(bodyParser.json());                                    
app.use(bodyParser.urlencoded({extended: true}));              
app.use(bodyParser.text());                                    
app.use(bodyParser.json({ type: 'application/json'}));  

app.get("/", (req, res) => res.json({message: "User management app"}));

app.route("/user")
.get(user.getUsers)
.post(user.createUser);
app.route("/user/:id")
.delete(user.deleteUser)
.put(user.updateUser);
app.listen(port);
module.exports = app;


Models

Next, we are going to create models for our application. Create a folder called models and inside this folder, create a file named user.js. Fill the file with the contents below:

let mongoose = require('mongoose');
let Schema = mongoose.Schema;

let UserSchema = new Schema(
  {
    firstName: { type: String, required: true },
    lastName: { type: String, required: true },
    emailAddress: { type: String, required: true },
    username: { type: String, required: true},
    password: { type: String, required: true },    
  },
  {
    versionKey: false
  }
);

module.exports = mongoose.model('user', UserSchema);

It is time to run our application. First off, install the required packages, i.e npm install, then run the application, npm start. You can browse the app on port 5000 using Postman. For example:


CREATE:

CREATE:

READ 

READ


UPDATE 

The above tests may fool you that the app is 100% functional, without flaws. This is not the case. We should write tests to prove that our app is functioning as expected.

Tests

Mocha by default expect a folder called test. Let’s create the folder, and inside this folder, create a test file called user.js . Populate the file with the following contents:



As you are familiar with JS, in the above code block, I’m just importing the required packages and files, for our tests to run successfully. 

Next, create the parent block for the tests:

Tests


We want the db to be cleared before each test is executed. Mocha has what we call beforeEach . This runs a block of code before each test in a describe. 

Tests

Next, let’s add a test which is going to test the creation of a user: 

Tests

The code block above, first ensures that a user cannot be created without an E-mail address. It also proves that actually when valid data is posted to the /user endpoint, a user is created successfully. 

Let’s test this. Run npm test. The result should be as follows:

Tests

A complete user.js test file, which has tests addressing, CREATE, READ, UPDATE AND DELETE, is as shown below. The code is self-explanatory. Copy the code and update the test file that you have so far.

let mongoose = require("mongoose");
let User = require('../models/user');
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('../index');
let should = chai.should();


chai.use(chaiHttp);

describe('Users', () => {
beforeEach((done) => {
User.remove({}, (err) => {
   done();  
});
    });
 
    describe('/POST user', () => {
        it('it should not create a user without email address', (done) => {
            let user = {
                firstName: "John",
                lastName: "Doe",
              username: "user",
              password: "pass"
            }
              chai.request(server)
              .post('/user')
              .send(user)
              .end((err, res) => {
                    res.should.have.status(200);
                    res.body.should.be.a('object');
                    res.body.should.have.property('errors');
                    res.body.errors.emailAddress.should.have.property('kind').eql('required');
                done();
              });
        });
       
        it('it should create a user ', (done) => {
          let user = {
              firstName: "John",
              lastName: "Doe",
              emailAddress: "doe@email.com",
              username: "me",
              password: "pass"
          }
              chai.request(server)
              .post('/user')
              .send(user)
              .end((err, res) => {
                    res.should.have.status(200);
                    res.body.should.be.a('object');
                    res.body.should.have.property('message').eql('User successfully created');
                    res.body.user.should.have.property('firstName');
                    res.body.user.should.have.property('lastName');
                    res.body.user.should.have.property('emailAddress');
                    res.body.user.should.have.property('username');
                done();
              });
        });
    });

  describe('/GET user', () => {
  it('it should GET all the users', (done) => {
chai.request(server)
    .get('/user')
    .end((err, res) => {
  res.should.have.status(200);
  res.body.should.be.a('array');
  res.body.length.should.be.eql(0);
      done();
    });
  });
  });


  describe('/PUT/:id user', () => {
  it('it should update a user given an id', (done) => {
  let user = new User({firstName: "John", lastName: "Doe", emailAddress: "doe@email.com", username: "user", password: "pass"})
  user.save((err, user) => {
chai.request(server)
    .put('/user/' + user.id)
    .send({firstName: "John", lastName: "Doe", emailAddress: "john@email.com", username: "user", password: "pass"})
    .end((err, res) => {
  res.should.have.status(200);
  res.body.should.be.a('object');
  res.body.should.have.property('message').eql('User updated');
  res.body.user.should.have.property('emailAddress').eql("john@email.com");
      done();
    });
  });
  });
  });

  describe('/DELETE/:id user', () => {
  it('it should delete a user given an id', (done) => {
  let user = new User({firstName: "John", lastName: "Doe", emailAddress: "doe@email.com", username: "user", password: "pass"})
  user.save((err, user) => {
chai.request(server)
    .delete('/user/' + user.id)
    .end((err, res) => {
  res.should.have.status(200);
  res.body.should.be.a('object');
  res.body.should.have.property('message').eql('User deleted');
      done();
    });
  });
  });
  });
});

Running the tests, you should have something similar to:

Tests

Conclusion

If you’ve keenly followed the above steps from installing Mocha and Chai on Node JS to testing Node JS code with Mocha and Chai, you should be having a functional app with passing tests.

This tutorial doesn’t exhaustively cover Mocha testing. There are other concepts which I haven’t illustrated here. For a deeper understanding, you can head on to the docs.

Please don’t confuse the above with TDD. After understanding how to test an application, we can build an application using principles of TDD. Hopeful, that’s my next tutorial. Stay tuned!

 

Delan

Delan collins

Blog author
I'm a DevOps Engineer and a Blockchain enthusiast. I like open source technologies. I believe in sharing of knowledge with others.
Website : https://github.com/collins-b

Leave a Reply

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

Top comments

software testing

31 October 2018 at 12:15pm
Hi Delan, Great post! First of all, I want to thanks to this site,its really a amazing place where anyone can enhance his/her knowledge related to <a href="https://crbtech.in/programmes/software-testing-training-programme/">testing</a>. Each step were explained very clearly. It’s easy to understand for me. keep up the immense work!

Achraya

16 November 2018 at 3:54pm
Very useful article, thanks so much!

SUBSCRIBE OUR BLOG

Follow Us On

Share on

other Blogs

20% Discount