Mocha is a unittest framework for Node. In this document, we explain how you can test your javascript code and also your HTTP servers.
Use npm
to install Mocha:
npm install mocha
npm
installs Mocha in node_modules/mocha/bin/mocha
.
You can run Mocha test cases using the following command:
node_modules/mocha/bin/mocha test
By default, Mocha will run test.js
in the current folder.
Now, let's explain how you can write a test case.
Let say, we have a calc.js
file that implements addition
and multiplication:
exports.add = function(i, j) {
return i + j;
};
exports.mul = function(i, j) {
return i * j;
};
We should write unit tests to make sure that there is no bugs
in add
and mul
. We implement our test cases in test.js
:
var assert = require('assert');
var calc = require('./calc.js');
// Tests are hierarchical. Here we define a test suite for our calculator.
describe('Calculator Tests', function() {
// And then we describe our testcases.
it('returns 1+1=2', function(done) {
assert.equal(calc.add(1, 1), 2);
// Invoke done when the test is complete.
done();
});
it('returns 2*2=4', function(done) {
assert.equal(calc.mul(2, 2), 4);
// Invoke done when the test is complete.
done();
});
});
assert
is a standard module that provides easy-to-use assertion
functions. calc
is our calculator module.
describe
creates a suite of test cases, and it
implements a
test case. The first argument to it
is an explanation of
the test case, and the second parameter is the test case function to
which Mocha passes a done
object. done
should be called
whenever the test case is finished.
Inside the test case function, you should implement your test.
For example, we have checked that add(1, 1)
returns 2
, and
mul(2, 2)
return 4
.
Now, if you run Mocha you should see the following output:
# node_modules/mocha/bin/mocha test
Calculator Tests
✓ returns 1+1=2
✓ returns 2*2=4
2 passing (6ms)
Usually we test much larger applications, and we need a better
categorization for our test cases. For that reason, you can
embed a describe
in another describe
. For instance, if
we want to have separate test cases for addition and multiplication,
we implement test.js
as follows:
var assert = require('assert');
var calc = require('./calc.js');
describe('Calculator Tests', function() {
describe('Addition Tests', function() {
it('returns 1 + 1 = 2', function(done) {
assert.equal(calc.add(1, 1), 2);
done();
});
it('returns 1 + -1 = 0', function(done) {
assert.equal(calc.add(1, -1), 0);
done();
});
});
describe('Multiplication Tests', function() {
it('returns 2 * 2 = 4', function(done) {
assert.equal(calc.mul(2, 2), 4);
done();
});
it('returns 0 * 4 = 4', function(done) {
assert.equal(calc.mul(2, 2), 4);
done();
});
});
});
For this test.js
, you should get the following output:
# node_modules/mocha/bin/mocha test
Calculator Tests
Addition Tests
✓ returns 1 + 1 = 2
✓ returns 1 + -1 = 0
Multiplication Tests
✓ returns 2 * 2 = 4
✓ returns 0 * 4 = 4
4 passing (6ms)
There is nothing special about testing a server except that we need to run the server to be able to test that. Well, you shouldn't do that manually. After all, unit tests are all about automation.
Let's first write a simple HTTP server that
echos 'Hello, Mocha!'
when we send a get request
to /
:
var http = require('http');
// This is just an example HTTP server. Use your own application here.
var server = http.createServer(function(req, res) {
res.writeHead(200);
res.end('Hello, Mocha!');
});
// listen strats the server on the given port.
exports.listen = function(port) {
console.log('Listening on: ' + port);
server.listen(port);
};
// close destroys the server.
exports.close = function() {
server.close();
};
You can use any framework that you'd like including
express.js
. The only important point is that
you should somehow export the functions to start and
stop the server. Here, we have exported listen(port)
and
close()
.
Now, let's implement test.js
:
var http = require('http');
var assert = require('assert');
var server = require('./server.js');
describe('HTTP Server Test', function() {
// The function passed to before() is called before running the test cases.
before(function() {
server.listen(8989);
});
// The function passed to after() is called after running the test cases.
after(function() {
server.close();
});
describe('/', function() {
it('should be Hello, Mocha!', function(done) {
http.get('http://127.0.0.1:8989', function(response) {
// Assert the status code.
assert.equal(response.statusCode, 200);
var body = '';
response.on('data', function(d) {
body += d;
});
response.on('end', function() {
// Let's wait until we read the response, and then assert the body
// is 'Hello, Mocha!'.
assert.equal(body, 'Hello, Mocha!');
done();
});
});
});
});
});
before
and after
are the functions you can
use to run a code before starting and after finishing
all testcases in your suite. In our example,
we start run the server on port 8989 in before
,
and close it in after
.
Now, we know that the server will be running.
So, we just send a get request using http.get()
,
read the response, and make sure that the server
has echoed 'Hello, Mocha!'
Have fun hacking with Mocha!
Great Tutorial! Thanks!