Nodeunit没有检测到done()

时间:2013-11-07 12:34:45

标签: node.js gruntjs nodeunit

尝试使用node.js和nodeunit加快速度,但我发现nodeunit存在一个问题,即在其中一个测试中没有看到test.done()的调用。

代码:

// Added for clarity.
var client = require("restify").createJsonClient({
    "version": "*",
    "url": "http://localhost:" + server.Port
});

exports["tests"] = {
    "setUp": function (callback) {
        server.StartServer();
        callback();
    },
    "tearDown": function (callback) {
        callback();
    },
    "CanIHaveSomeTeaPlease?": function (test) {
        test.expect(4);
        client.get("/tea", function (err, req, res, data) {
            test.equal(err.statusCode, 418, "Expected ImATeapot Error.");
            test.equal(err.message, "Want a biscuit?", "Expected to be asked if I want a buscuit.");
            test.equal(err.restCode, "ImATeapotError");
            test.equal(err.name, "ImATeapotError");
            test.done();
        });
    },

    // Note: I expect this test to fail as it is a copy of the above
    //       test on a different url that doesn't return the ImATeapot
    //       HTTP error. But it doesn't look like it's detecting it
    //       properly.

    "TakeThisInfo": function (test) {
        test.expect(4);
        client.put("/push", {
            "hello": "world"
        }, function (err, req, res, data) {
            test.equal(err.statusCode, 418, "Expected ImATeapot Error.");
            test.equal(err.message, "Want a biscuit?", "Expected to be asked if I want a buscuit.");
            test.equal(err.restCode, "ImATeapotError");
            test.equal(err.name, "ImATeapotError");
            test.done();
        });
    }
};

输出:

FAILURES: Undone tests (or their setups/teardowns):
- tests - TakeThisInfo

To fix this, make sure all tests call test.done()

我希望这是愚蠢的事。

版本: -

Node: 0.10.21
NPM: 1.3.11
Nodeunit: 0.8.2
Grunt-CLI: 0.1.10
Grunt: 0.4.1

4 个答案:

答案 0 :(得分:3)

首先,我不知道你的代码中有什么“服务器”,但我希望它是异步的,所以在你的setUp函数中有更多这样的东西:

function (callback) {
  server.StartServer(function(){
    callback();
  });
}

其次,保持同时出现nodeunit executes the startUp and the tearDown functions after and before EVERY test所以我怀疑你正在启动服务器2次(就像在tearDown中你没有真正关闭它一样)。

答案 1 :(得分:2)

我花了最后几个小时搞乱这个问题,而且已经清楚的是,nodeunit无法捕获并显示在IO或setTimeout类型进程稍后触发的函数中抛出的异常。考虑到JavaScript的运行方式,这并不奇怪。一旦您确定没有例外,一切正常,但如果您的代码中有错误,您将获得“撤消测试”消息,而不是其他任何内容。以下是我为解决问题所做的工作(以解析路线为例):

function myRoute(req, res, next) {
    try {
        // your code goes here...
    }
    catch (err) {
        // write it to the console (for unit testing)
        console.log(err);
        // pass the error to the next function.
        next(err);
    }
}

一旦我以这种方式理解了这个问题,修复它就会更清楚了,我能够通过所有的测试!

答案 2 :(得分:1)

我怀疑你在第二次测试中实际上没有调用test.done()。在那里拨打console.log()电话,以验证您是否正在拨打该电话。

FWIW,我在下面使用您的测试的简化版本重新描述了所描述的问题。如果省略on('error', function() {...})处理程序,则第二次测试无法完成。因此,我的理论是你的/push端点在restify模块中触发了不同的行为。即你确定 restify是在那里用err属性来调用你的回调,还是它做了不同的事情? ...例如,在下面发出类似http.get的事件。

var http = require('http');

exports.test1 = function (test) {
  test.expect(1);
  http.get({hostname: "www.broofa.com", path: "/"}, function (res) {
    test.equal(res.statusCode, 200, 'got 200');
    test.done();
  });
};

exports.test2 = function (test) {
  test.expect(1);
  http.get({hostname: "www.no-such-domain.com", path: "/"}, function (res) {
    test.equal(res.statusCode, 200, 'got 200');
    test.done();
  }).on('error', function() {
    // Comment line below out to repro the "Undone tests" error
    test.done();
  });
};

答案 3 :(得分:1)

我正在通过在服务器中将服务器分配到自己的进程中然后在拆解中将其杀死来解决它。认为问题与正在创建的服务器有关,而不是关闭。谢谢@matteofigus。

var cp = null; // child process
exports["tests"] = {
    "setUp": function (callback) {
        cp = fork("./lib/server.js", {"silent": true});
        callback();
    },
    "tearDown": function (callback) {
        cp.kill("SIGHUP");
        callback();
    },
    "CanIHaveSomeTeaPlease?": function (test) {
        test.expect(4);
        client.get("/tea", function (err, req, res, data) {
            test.equal(err.statusCode, 418, "Expected ImATeapot Error.");
            test.equal(err.message, "Want a biscuit?", "Expected to be asked if I want a buscuit.");
            test.equal(err.restCode, "ImATeapotError");
            test.equal(err.name, "ImATeapotError");
            test.done();
        });
    },
    "TakeThisInfo": function (test) {
        test.expect(1);
        client.put("/push", {
            "hello": "world"
        }, function (err, req, res, data) {
            test.ok(false);
            test.done();
        });
    }
};