Select Page
Technorati Tags: ,

The code

Let’s say you have a Node module (named potentialPartner.js) that returns a promise, as such:

var Q = require("q");

function willYouLoveMe(cond){
	var deferred = Q.defer();

	if (cond === "even if I were out of shape")
		deferred.reject("I only like guys in shape");
	else
		deferred.resolve("I love you unconditionally!");

	return deferred.promise;
}

module.exports = {
	willYouLoveMe: willYouLoveMe
};

How can we test it?

To cover all scenarios, you’ll need a way to exercise all possible outcomes of the promise (in this case a fulfilled promise, and a rejected rejected promise). Using mocha, should, and (obviously) Q, here’s what the tests may look like:

var should = require("should"),
	Q = require("q");

describe("A potential partner", function() {
	var potentialPartner = require("../potentialPartner");

	it("should promise to love me", function() {
		var promise = potentialPartner.willYouLoveMe();

		promise.should.have.property("then");
		promise.should.have.property("fail");
	});

	it("should promise to love me unconditionally", function(done) {
		var promise = potentialPartner.willYouLoveMe("no matter what");

		promise.done(function(){ // onFulfilled
			done();
		}, function() { // onRejected
			should.fail("I expect my partner to love me unconditionally!");
			done();
		});
	});

	it("should not promise to love me ONLY if I'm in shape", function(done) {
		var promise = potentialPartner.willYouLoveMe("even if I were out of shape");

		promise.done(function(){ // onFulfilled
			should.fail("I expect my partner to not just promise me to love me if I'm in shape :(");
			done();
		}, function() { // onRejected
			done();
		});
	});
});

Note that:

  1. The very first test (“should promise to love me”) is probably unnecessary. However, I like to have very specific tests that make the failure obvious when they fail. This makes them more effective, and the failures quicker to debug.
  2. I’m using mocha’s done function to handle the async results from the method under test. Otherwise, the async tests will complete before the assertions are executed, which will cause mocha to report false positives.
  3. I’m using promise.done() to hook up my assertions. This is key! … you may feel inclined to chain a then to your promise, or a fail (depending on the condition you want to test), but the main problem with that has to do with the way exceptions are handled internally by then/fail. The bottom line is that such handling can cause issues with your failing assertions and the way they end up getting reported by the test framework (it can hamper debug-ability). Instead, promise.done() plays more nicely with your test reports.