Using Mocha, Chai and Sinon to test Node.js
Marco Franssen

Loading...
Marco Franssen

In this article, I'm going to show you how to test your Node.js application using Mocha, Chai and Sinon. We'll cover synchronous return values, asynchronous callbacks and events with a small calculator example.
Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.
One of the cool things about Mocha is that you can choose your own assertion style. In this article, I'll use Chai for my assertions.
Chai is a BDD/TDD assertion library for Node.js and the browser that can be delightfully paired with any JavaScript testing framework.
Chai supports three assertion styles: Should, expect and assert. This makes Mocha and Chai a great combination for tailoring your test suite to your project's needs and your own preferences.
I've chosen Sinon as my mocking framework, since it integrates neatly with Mocha, Chai and dozens of other test frameworks.
Standalone test spies, stubs and mocks for JavaScript. No dependencies; works with any unit testing framework.
Before we can write our tests, we need to install Mocha, Chai and Sinon. Since I use Mocha for multiple projects, I've chosen to install it globally.
npm install -g mocha
npm install --save-dev mocha chai sinonTo make sure developers working with my Node.js package also have Mocha available, I add it to the development dependencies as well. Since I've installed Mocha globally, it won't be installed in my package folder again. Now we can start writing our tests.
Let's assume our package has the following folder structure.
MyMochaChaiSinonExample
|_ lib
|_ spec
|_ helpersThe lib folder contains our JavaScript modules. We'll save our tests, or specifications, in the spec folder and our test helper scripts in the helpers folder.
First, I want to configure Chai so we don't have to repeat the configuration in every test. To do that, I create a file called chai.js in the specs/helpers folder.
var chai = require("chai");
chai.config.includeStack = true;
global.expect = chai.expect;
global.AssertionError = chai.AssertionError;
global.Assertion = chai.Assertion;
global.assert = chai.assert;This configuration tells Chai to include a stack trace when an assertion fails. It also makes Chai's expect and assert methods available globally. We'll require this helper file when running our tests with Mocha.
Next, we can write tests to cover the code in lib. Let's assume we have a calculator that we want to unit test.
var EventEmitter = require("events").EventEmitter,
util = require("util"),
processResult = function (calculator, result, callback) {
calculator.emit("result", result);
if (typeof callback !== "undefined") {
setTimeout(
function () {
callback(result);
},
1000,
this
);
} else {
return result;
}
};
function Calculator() {
EventEmitter.call(this);
}
util.inherits(Calculator, EventEmitter);
Calculator.prototype.add = function (a, b, callback) {
var result = a + b;
return processResult(this, result, callback);
};
Calculator.prototype.substract = function (a, b, callback) {
var result = a - b;
return processResult(this, result, callback);
};
Calculator.prototype.multiply = function (a, b, callback) {
var result = a * b;
return processResult(this, result, callback);
};
Calculator.prototype.divide = function (a, b, callback) {
var result = a / b;
return processResult(this, result, callback);
};
module.exports = Calculator;The calculator supports three ways to return a result: synchronously through a return value, and asynchronously through a callback or an event. First, I'll show you how to write a synchronous test for the return value.
var Calculator = require("../lib/calculator");
describe("When adding one and two using the calculator", function () {
var calculator;
before(function () {
calculator = new Calculator();
});
it("should result in three using the return style approach", function () {
var result = calculator.add(1, 2);
expect(result).equal(3);
});
});This test is pretty straightforward. We describe the test case, create a calculator in the before hook, then make our assertion. Here, we're using Chai's expect style. In the next example, I'll show you how to test asynchronous code using the callback approach, which delays the result by one second.
var Calculator = require("../lib/calculator");
describe("When substracting six and eight using the calculator", function () {
var calculator;
before(function () {
calculator = new Calculator();
});
it("should result in minus two the callback approach", function (done) {
calculator.substract(6, 8, function (result) {
assert.equal(result, -2);
done();
});
});
});In this test, I've used a different assertion style, assert. Also notice the done callback parameter: we call it to tell Mocha that the test has completed.
For the last example, I want to show you how to check whether a function is called using a Sinon stub and spy. I'll test the calculator's event approach and make sure the result event is emitted before the callback is invoked.
var Calculator = require("../lib/calculator"),
sinon = require("sinon");
describe("When multiplying nine and three using the calculator", function () {
var calculator, eventEmitterStub, callbackSpy, clock;
before(function () {
calculator = new Calculator();
clock = sinon.useFakeTimers();
eventEmitterStub = sinon.stub(calculator, "emit");
callbackSpy = sinon.spy();
});
it("should emit the event before the callback", function (done) {
calculator.multiply(9, 3, callbackSpy);
clock.tick(1000);
assert.equal(callbackSpy.called, true);
assert.equal(eventEmitterStub.calledWithExactly("result", 27), true);
assert.equal(eventEmitterStub.calledBefore(callbackSpy), true);
done();
});
after(function () {
clock.restore();
});
});Since the callback is invoked after one second, I want to make sure the calculation has finished before my assertions run. That's why we use Sinon's fake timers. Advancing the clock lets us check that the callback was called and that emit was called before it. Without advancing the clock, the assertion on the spy would fail because the callback hasn't executed yet. The stub lets us monitor calls to the emit method inherited from EventEmitter.
Now let's run these tests with Mocha. The following command executes all the tests in our specs folder.
mocha specs --require specs/helpers/chai.jsFor more visual feedback, use the following command. The command above only shows dots.
mocha specs --require specs/helpers/chai.js --reporter specAs a bonus, here's my Grunt configuration for running the tests automatically with a watch task. I only include files ending in *.spec.js, so the helper scripts won't be treated as test files. That's the naming convention I've chosen for all my test specifications.
mochaTest: {
specs: {
options: {
ui: 'bdd',
reporter: 'spec',
require: './specs/helpers/chai'
},
src: ['specs/**/*.spec.js']
}
}
/////////////////////////////////////////////
grunt.LoadNpmTasks('grunt-mocha-test');Add the mochaTest task to your watch task so the tests run automatically. Don't forget to install grunt-mocha-test and save it in your package.json:
npm install --save-dev grunt-mocha-testLast but not least, here are some helpful links to all three frameworks.
Hopefully, this article gives you a quick start with testing your own Node.js packages using Mocha, Chai and Sinon. I'd also like to challenge you to try Mocha for testing your browser JavaScript. Feel free to share your experiences and questions in a comment.
Marco Franssen
Customize a Debian VirtualBox VM with Packer user variables, file uploads, and shell provisioners in this 2014 tutorial covering MySQL and Apache setup.
Marco Franssen
Build a reproducible Debian Wheezy VM with Packer and VirtualBox in this 2014 tutorial, using a JSON template and preseed file for unattended installation.
Marco Franssen
Automate development and CI tasks with Grunt: configure a Gruntfile, run task targets, combine tasks, and watch files to rerun jobs when they change.
Marco Franssen
Learn how to initialize, install, update, and publish Node.js packages with npm in this 2013 walkthrough, including development dependencies and private packages.