Monday, July 4, 2011

A simple introduction to TDD with Expresso in NodeJS

In the last post we made a super simple NodeJS module called hello.js and used it in app.js. We can make it better, and test it with Expresso.

First we can add to the awesomeness of hello.js by adding a farewell function, so it can say both "hello" and "goodbye".

// hello.js
var greeting="Hello World!";
var farewell="Goodbye Cruel World!";
var greet = function(){
    return greeting;
};
var leave = function() {
    return farewell;
};
exports.greet = greet;
exports.leave = leave;

So now our module can say hello, and bid farewell.  It exports the "greet" and "leave" functions, which we can use from app.js like so:

// app.js
var hello=require('./lib/hello.js'); 
console.log(hello.greet());
console.log(hello.leave());

Notice that I moved hello.js into a new directory called "lib", which is why the require statement now says "require('./lib/hello.js')".

Now suppose we want to test this module using expresso.  Since expresso is a command-line utility, we should install it globally:

npm install -g expresso

Now we can write a test.  First we make a "test" directory and then create a file called "hello.test.js".

mkdir test
vi test/hello.test.js

// test/hello.test.js
var assert = require('assert'),
      hello = require('hello.js);

module.exports = {
    'greet()': function() {
        assert.equal('Hello World!', hello.greet());
    }
};

This just requires node's built-in "assert" module for unit testing, plus our hello.js module that we want to test. Then, it defines a test to make sure that when we call "greet()", the response is "Hello World!". Alright! Now we can go back to the parent directory (where app.js lives) and run expresso. We tell it to look in the "lib" directory for hello.js. Expresso already knows to look in the "test" directory for tests, and will run everything it finds there.

$ expresso -I lib

    %100 1 tests

Wonderful.  Only, we didn't test the part where we say goodbye. Expresso has built-in code coverage reporting that we can enable with the "-c" flag:

$ expresso -I lib -c

   Test Coverage

   +------------------------------------------+----------+------+------+--------+
   | filename                                 | coverage | LOC  | SLOC | missed |
   +------------------------------------------+----------+------+------+--------+
   | hello.js                                 |    87.50 |   10 |    8 |      1 |
   +------------------------------------------+----------+------+------+--------+
                                              |    87.50 |   10 |    8 |      1 |
                                              +----------+------+------+--------+

   hello.js:

      1 | 1 | var greeting = "Hello World!";
      2 | 1 | var farewell  = "Goodbye Cruel World!";
      3 | 1 | var greet = function() {
      4 | 1 |    return greeting;
      5 |   | };
      6 | 1 | var leave = function() {
      7 | 0 |    return farewell;
      8 |   | };
      9 | 1 | exports.greet = greet;
     10 | 1 | exports.leave = leave; 

Cool. It tells us we haven't tested the part about leaving with a farewell. All we have to do if we want 100% code coverage is to define a test for "leave":

// test/hello.test.js
var assert = require('assert'),
    hello = require('hello.js');

module.exports = {
   'greet()': function() {
       assert.equal('Hello World!', hello.greet());
   }, 
   'leave()': function() {
       assert.equal('Goodbye Cruel World!', hello.leave());
   }
};


And now when we run expresso again, we should have 100% code coverage.

$ expresso -I lib -c

  Test Coverage

   +------------------------------------------+----------+------+------+--------+
   | filename                                 | coverage | LOC  | SLOC | missed |
   +------------------------------------------+----------+------+------+--------+
   | hello.js                                 |   100.00 |   10 |    8 |      0 |
   +------------------------------------------+----------+------+------+--------+
                                              |   100.00 |   10 |    8 |      0 |
                                              +----------+------+------+--------+

   hello.js:

      1 | 1 | var greeting = "Hello World!";
      2 | 1 | var farewell  = "Goodbye Cruel World!";
      3 | 1 | var greet = function() {
      4 | 1 |    return greeting;
      5 |   | };
      6 | 1 | var leave = function() {
      7 | 1 |    return farewell;
      8 |   | };
      9 | 1 | exports.greet = greet;
     10 | 1 | exports.leave = leave; 

Cool, eh?

Expresso offers several other assert functions that you can find in the documentation here: http://visionmedia.github.com/expresso/.

No comments:

Productivity and Note-taking

I told a friend of mine that I wasn't really happy with the amount of time that gets taken up by Slack and "communication and sched...