Tue, 2012-04-24 18:31

Topics: 
Mocha is a feature-rich JavaScript test framework running on Node and 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. --- http://visionmedia.github.com/mocha/
Okay, the modern fashion is for the developer to write unit tests alongside their code.  In the Node community there has been several unit testing frameworks developed with different approaches in mind.  While at Yahoo I was using YUITest because, well, YUI is Yahoo's thing and we thought it would be best to use Yahoo's thing.  While it worked fairly well on Node, it had a major issue in that it did little to help us with testing asynchronous code.  I haven't looked at too many of the other unit test frameworks, but recently came across Mocha and it looks pretty nice, and has a nice solution for testing asynchronous code.
Installs with npm:  $ npm install -g mocha

An example of a test case is:

describe('Array', function(){
describe('#indexOf()', function(){
it('should return -1 when the value is not present', function(){
[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);
})
})
})

Or

describe('Context', function(){
beforeEach(function(){
this.calls = ['before'];
})

describe('nested', function(){
beforeEach(function(){
this.calls.push('before two');
})

it('should work', function(){
this.calls.should.eql(['before', 'before two']);
this.calls.push('test');
})

after(function(){
this.calls.should.eql(['before', 'before two', 'test']);
this.calls.push('after two');
})
})

after(function(){
this.calls.should.eql(['before', 'before two', 'test', 'after two']);
})
})

What we see is the "describe" function is a container for test cases, the "it" function is a test case which is read as "it should _____".

There are some extra functions, before(), after(), beforeEach(), and afterEach(), which are called at various stages in the test suite execution.  The functions before and after would be called at the beginning and end of executing a describe block, while beforeEach and afterEach are called before and after each test case.

The examples so far are using the BDD style of writing tests.  Mocha also supports other styles, see the website for more details.

Now, what about asynchronous code?

describe('User', function(){
describe('#save()', function(){
it('should save without error', function(done){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
done();
});
})
})
})

Basically, the test case either throws an exception, or calls done().  If the test function doesn't take a function argument, as in the earlier examples, then Mocha doesn't treat it as an asynchronous test.  However if the test function does take a function argument, then the test is not finished until either an exception is thrown or the done() function is called.

This makes it relatively easy to encapsulate asynchronous code within a test case.

However there is an issue with this example.  See it?  What if the callback inside the test case is never called?  Neither an exception will be thrown, nor will the done() function be called, hence Mocha will hang at that test case.

There are two ways to fix this:

  1. Use the --timeout option so that if a test case does not finish within the timeout period, the test case will fail
  2. Call this.timeout(500) inside the test function if a given test needs a different timeout from the global timeout
Mocha also includes a long list of output formats, named reporters, that govern the output printed on the console.  The reporters vary from extremely terse (a line of dot's) to very verbose, with color coded output, etc.  While nice for the developer, pretty output on the terminal isn't so good for gathering long-term test results data to look at test failure trends etc.   It supports the TAP format, JSON, etc.  It doesn't seem to support JUnit format output for some reason, but TAP and JSON should be enough for reporting.
An interesting reporter is the doc reporter that provides a nice annotated HTML page of the test collections, and the "should" phrases.