node.jsnodeunit

How to write a helper function for different assert functions in nodeunit


I want to write a helper function that either asserts a test function given as an argument or calls assert.equal by default.

When running the code below, I get the following error: Expected 1 assertions, 0 ran

var assert = require('nodeunit').assert;

var interpretTest = function(expression, expected, testFunction) {
    testFunction = testFunction || assert.equal;
    return function(test) {
        test.expect(1);
        testFunction(expression, expected);
        test.done();
    };
};

exports.testEqual = interpretTest([8, 6], [8, 6], assert.deepEqual);

The tests pass when removing test.expect(1) but with 0 assertions.


Solution

  • The problem is that nodeunit wraps each assertion in some logic that keeps track of everything that is done within a test case. Expect sets the expected number of assertions, and when done is called it will simply check that the number of assertions that actually ran is what you expected.

    Since the test object is passed to every test function, it's hard to change its state from your helper function. I came up with the following solution:

    var getTestMethod = function(methodName) {
        return function(test) { return test[methodName]; };
    };
    
    var equal = getTestMethod('equal');
    var deepEqual = getTestMethod('deepEqual');
    
    var interpretTest = function(expression, expected, testMethodFactory) {
        testMethodFactory = testMethodFactory || equal;
        return function(test) {
            var testMethod = testMethodFactory(test);
            test.expect(1);
            testMethod(expression, expected);
            test.done();
        };
    };
    
    exports.testNumbers = interpretTest(8, 8);
    exports.testArrays = interpretTest([8, 6], [8, 6], deepEqual);
    

    Maybe you can find a way to simplify this, but it works. The getTestMethod returns a function that returns one of the assert methods on a test object.

    To use it, you pass the current test object to the factory method, which will return the assertion you need. This way you get the correct context for the current assertion.

    I guess you can think of getTestMethod as assertionFactoryFactory, but that sounds too evil.