Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodeunit test.throws doesn't seem to catch the error

I am trying to create a test suite for a module that I am writing in Node.js using Nodeunit. The module is a basic music playlist that allows adding and removing tracks to the playlist.

var playlist = function(){
    this.__playlist = [];
    this.__count = 0;
};

playlist.prototype = {
    addtrack:function(track){
        if(typeof track !== "object") throw new Error("Track needs to be an oject");
        this.__count++;
        track.id = this.__count;
        this.__playlist.push(track);
        return this.__playlist;
    },
    removetrack:function(trackid){
        if(typeof trackid !== "number") throw new Error("Pass in a numeric track id");
        var trackFound = false;
        for(var i=0;i<this.__playlist.length;i++){
            var t = this.__playlist[i];
            if(t.id == trackid){
                trackFound = true;
                this.__playlist.splice(i,1);
            }
        }
        if(!trackFound) throw new Error("Track not found in the playlist");
        return this.__playlist
    }
}

exports.playlist = function(){
    return new playlist();
}

As you can see there are places that throw errors based on incorrect data being passed in.

So here is my test suite.

var pl = require('./playlist');

exports.testPlaylistInit = function(test){
    var playlist = pl.playlist();
    test.equal(typeof playlist, 'object');
    test.done();
}

exports.testAddingTracks = function(test){
    var playlist = pl.playlist();
    test.throws(playlist.addtrack(), Error, 'Should fail for blank track');
    var track = {
        title: "Golly Sandra",
        artist: "Eisley",
        album: "Room Noises"
    };
    tracks = playlist.addtrack(track);
    test.equals(tracks[0],track);
    test.equals(tracks[0].id,1)
    test.done();
}

exports.testRemoveingTracks = function(test){
    var playlist = pl.playlist();
    test.throws(playlist.removetrack('Imma error'), Error, 'Show fail for non-numeric track id');
    var track = {
        title: "Golly Sandra",
        artist: "Eisley",
        album: "Room Noises"
    };
    playlist.addtrack(track);
    track = {
        title: ".44 Calliber Love Letter",
        artist: "Alexisonfire",
        album: "Alexisonfire"
    }
    playlist.addtrack(track);
    test.equals(playlist.removetrack(1)[0],track);
    test.throws(playlist.removetrack(10), Error, 'Should fail for non-existant track');
    test.done();
}

While writing the test suite I used test.throws as the assumption basically just wraps the code block in a try-catch statement and checks the catch against the error block. Apparently I am wrong though, because when I run the test with Nodeunit, Node displays the error message thrown by the module instead of the test suite catching the error. Am I using the test.throw case incorrectly?

like image 279
Dave Long Avatar asked Aug 11 '11 03:08

Dave Long


1 Answers

Your usage of test.throws isn't quite right. If you look at what you have:

test.throws(
  playlist.removetrack('Imma error'),
  Error,
  'Show fail for non-numeric track id'
);

You are executing playlist.removetrack('Imma error'), and then passing the result of that to throws, so if there is an exception, it will happen before throws is ever executed.

You should do something more like this:

test.throws(
  function() {
    playlist.removetrack('Imma error');
  }, 
  Error,
  'Show fail for non-numeric track id'
);

You must pass in a function, that when executed, will try to remove the track. That way, your playlist logic is actually executed by the throws function, and thus can automatically be wrapped in a try/catch block.

like image 155
loganfsmyth Avatar answered Sep 18 '22 20:09

loganfsmyth