debuggable

 
Contact Us
 

Unit testing with node.js

Posted on 30/1/10 by Felix Geisendörfer

Even so most stuff is fairly easy with node.js, unit testing takes a little bit of getting used to. The main difference to regular unit testing is that just because your test finishes running without an error, it doesn't mean there was no problem. But lets start with the basics.

Node.js has adopted the CommonJS assert module specification. You may also find references to mjsunit, but node no longer uses this library.

Lets have a look at how to write a basic test with node, lets call it my-test.js:

var assert = require('assert');

// Will pass
assert.ok(true);

// Will throw an exception
assert.ok(false);

Running this test will produce the following output:

$ node my-test.js
AssertionError: true == false
    at Object. (my-test.js:7:8)
    at [object Object]. (node.js:928:23)
    at [object Object].emitSuccess (node.js:240:15)
    at [object Object]. (node.js:653:21)
    at [object Object].emitSuccess (node.js:240:15)
    at node.js:510:29
    at node.js:985:1
    at node.js:989:1

One thing to note here is that, when node dies from an exception (which a failing assertion is), the exit code will be 1:

$ echo $?
1

But lets have a look at a more interesting unit test. Let's say you are writing a "hello world" web service called hello.js:

var http = require('http');

exports.server = http.createServer(function(req, res) {
  res.sendHeader(200, {'Content-Type': 'text/plain'});
  res.sendBody('hello world');
  res.finish();
});

To test this service, we can write a file called test-hello.js like this:

var
  assert = require('assert'),
  http = require('http'),
  hello = require('./hello'),
  callbackFired = false;

hello.server.listen(3000);

http
  .cat('http://localhost:3000/')
  .addCallback(function(data) {
    callbackFired = true;
    assert.equal('hello world', data);
    hello.server.close();
  });

process.addListener('exit', function() {
  assert.ok(callbackFired);
});

What's important in this test is that we are checking for two things here.

The first is the obvious assertion that the web service outputs the content we expect, nothing too exciting here.

The second is declaring the variable callbackFired and checking its value in the process 'exit' event. You could get away with not doing it for this particular test, because the test would never finish without the hello.server.close() line getting executed. For more complex tests however, it becomes incredibly important to keep in mind that a callback may never fire, something you can only catch with little helper variables like this.

If you need some more inspiration for testing different stuff with node, you should start by going over the test suite that comes with it.

Let me know if you have any questions!

-fg

 
&nsbp;

You can skip to the end and add a comment.

TJ Holowaychuk said on Jan 30, 2010:

Would be nice if we eventually went with JSpec http://jspec.info,
what we have is not terrible but in many cases not descriptive at all

Felix Geisendörfer said on Jan 30, 2010:

TJ Holowaychuk: I wouldn't mind something more descriptive, but I'm very skeptic of using with/eval to create DSLs. JS is just not that kind of language, and we should embrace that rather than trying to work against it : ).

TJ Holowaychuk said on Jan 30, 2010:

To each their own, I dont find harm in it. Either it is semi-descriptive and rapes the global scope, or very descriptive and uses a bit of hackery, I would personally go with the hacking. If you guys are interested I could come up with a quick bdd module without any magic

This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.