DailyJS

Testing with Mocha

Alex R. Young

Subscribe

@dailyjs

Facebook

Google+

tutorials testing node modules

Testing with Mocha

Posted by Alex R. Young on .
Featured

tutorials testing node modules

Testing with Mocha

Posted by Alex R. Young on .

Mocha (GitHub: visionmedia / mocha, npm: mocha, License:
MIT) by TJ Holowaychuk is a new test library that does just about everything a JavaScript developer needs, and yet remains customisable
enough to support both behaviour-driven and test-driven development
styles.

Mocha presents itself as an unassuming and lightweight library, but it
actually goes far beyond the test frameworks I'm familiar with in Node.
I've written literally hundreds of tests for various Node apps, and the
experience hasn't always been positive. Even popular test libraries lack
functionality that asynchronous, database-driven web apps require for
sane testing. My recommendation is to take Mocha seriously and give it a
try -- it's surprisingly intuitive.

The Basics

Mocha is available through npm, but I install it by adding it to my
package.json files. Make a package.json file
like this one:

{
    "name": "async-testing-tutorial"
  , "version": "0.0.1"
  , "description": "A tutorial for Mocha"
  , "keywords": ["test", "tutorial"]
  , "author": "Alex R. Young "
  , "main": "index"
  , "engines": { "node": ">= 0.4.x < 0.7.0" }
  , "scripts": {
    "test": "make test"
  }
  , "devDependencies": {
    "mocha": "0.3.x"
  }
}

Then run npm install and you're almost ready to use Mocha.
The Mocha script will be in ./node_modules/.bin/mocha, so
rather than typing this every time add a simple Makefile to
your project:

test:
    @./node_modules/.bin/mocha

.PHONY: test

While you're at it, add a test/ directory:

mkdir test

Now typing make test will run any tests in
test/!

Any options for Mocha can now be added to the Makefile:

test:
    @./node_modules/.bin/mocha -u tdd

.PHONY: test

This says we want to run tests in the TDD style:

The "BDD" interface provides describe(), it(), before(), after(), beforeEach(), and afterEach(). The "TDD" interface provides suite(), test(), setup(), and teardown().

Testing Synchronously

We'd better write something! Add this to index.js:

function nextPrime(n) {
  var smaller;
  n = Math.floor(n);

  if (n >= 2) {
    smaller = 1;
    while (smaller * smaller <= n) {
      n++;
      smaller = 2;
      while ((n % smaller > 0) && (smaller * smaller <= n)) {
        smaller++;
      }
    }
    return n;
  } else {
    return 2;
  }
}

module.exports.nextPrime = nextPrime;

This is just an excuse to do something, it's not meant to be the world's
greatest prime number generator. One reason I like this function is
large numbers will make the interpreter really slow, which can be
useful for demonstrating certain run-loop related issues.

Now create a new file called test/test.next-prime.js:

var assert = require('assert')
  , nextPrime = require('./../index').nextPrime
  , asyncPrime = require('./../index').asyncPrime;

suite('nextPrime', function() {
  test('nextPrime should return the next prime number', function() {
    assert.equal(11, nextPrime(7));
  });

  test('zero and one are not prime numbers', function() {
    assert.equal(2, nextPrime(0));
    assert.equal(2, nextPrime(1));
  });
});

And run make test in the terminal. The test should pass:

Why is this simple test interesting? Well, Mocha explicitly supports
asynchronous testing, yet we didn't have to tell it that the test had
finished running. To do that, we'd write a test like this:

var assert = require('assert')
  , nextPrime = require('./../index').nextPrime;

suite('nextPrime', function() {
  test('nextPrime should return the next prime number', function(done) {
    assert.equal(11, nextPrime(7));

    // Tell Mocha the test has finished
    done();
  });
});

How is Mocha able to achieve this amazing feat of introspection? It's
actually just checking how many arguments the callback has by using the
length property on Function. This makes the
API able to cope with both synchronous and asynchronous tests without
any extra boilerplate coding. If you want to read more about this, MDN:
Function
length

has examples.

Asynchronous Tests

Expanding on nextPrime, I've added a contrived asynchronous
version:

function nextPrime(n) {
  var smaller;
  n = Math.floor(n);

  if (n >= 2) {
    smaller = 1;
    while (smaller * smaller <= n) {
      n++;
      smaller = 2;
      while ((n % smaller > 0) && (smaller * smaller <= n)) {
        smaller++;
      }
    }
    return n;
  } else {
    return 2;
  }
}

function asyncPrime(n, fn) {
  setTimeout(function() {
    fn(nextPrime(n));
  }, 10);
}

module.exports.nextPrime = nextPrime;
module.exports.asyncPrime = asyncPrime;

The asyncPrime method just wraps the old function with
setTimeout to simulate an asynchronous call. Now we need to
use the done function provided by Mocha to signal the end
of the test:

suite('asyncPrime', function() {
  test('asyncPrime should return the next prime number', function(done) {
    asyncPrime(128, function(n) {
      assert.equal(131, n, 'Wrong number');
      done();
    });
  });
});

Mocha Tricks

Mocha comes packed with lots of test reporter format options, including
TAP and JSON, which provide opportunities for easy integration with other tools like
Continuous Integration (CI) services. TJ uses
Travis and has a little build status indicator on Mocha's README page.

Mocha also works with CoffeeScript and web browsers.

Sample Project

If you need help getting started with Mocha, I've put the code for this
tutorial on GitHub at alexyoung /
async-testing-tutorial
,
and TJ's projects use Mocha, which means popular libraries like
Express have plenty of examples to explore.