在mocha中测试nodeJS时,域没有正确捕获错误

时间:2013-10-19 01:14:49

标签: node.js mocha node.js-domains

当运行利用域进行错误处理的测试时,即使库中的域处理程序应该捕获到错误,Mocha仍然会出现错误。如果我在Mocha之外执行代码,它的功能正确,让我相信问题是Mocha。

示例:

foo.js

module.exports = function(done) {
    var domain = require("domain");
    var d = domain.create();

    d.on("error", function() {
        done();
    });

    d.run(function() {
        throw new Error("foo");
    });
}

test.js - foo.js内引发的错误未被域捕获。

describe("test", function() {
    it("should succeed", function(done) {
        var foo = require("./foo.js");
        foo(function() {
            console.log("done");
            done();
        });
    });
});

result : error thrown

script.js - 域正确捕获错误并冒泡。

var foo = require("./foo.js");
foo(function() {
    console.log("done");
});
result : done

正如您在上面所看到的,如果我直接向script.js节点它按预期运行,则域处理程序会捕获错误并继续执行代码。如果我在Mocha测试中运行相同的代码块,则错误将暂停测试并给出失败。我相信这是因为错误是在uncaughtException处理程序或类似的东西上发送的。另一个复杂的问题是它在Mocha中正常工作,如果我在函数调用周围有一个process.nextTick(),让我相信Mocha只能处理同步错误,但是对于异步错误可以正常工作。

这里有一些关于此问题的讨论:https://groups.google.com/forum/#!msg/nodejs/n-W9BSfxCjI/SElI1DJ_6u0Jhttps://github.com/joyent/node/issues/4375

我感到困惑的是,所有这些讨论似乎都说明问题已在几个月前得到解决。任何人都知道这个问题的简单解决方法,或者为什么我没有看到其他人似乎相信的错误已经修复了。

我在Windows 7上运行CentOS 6.3 Vagrant VirtualBox上的节点v0.10.18和Mocha 1.13.0。

2 个答案:

答案 0 :(得分:12)

发现问题。 NodeJS域捕获同步错误,但事件继续冒泡到try / catch 。如果将domain.run()包装在try/catch中,那么域错误处理程序和catch将被执行。

因此,最佳做法似乎是在所有domain.run()中使用process.nextTick。这在docs示例中显示,但并未按照我的意愿明确表达。

示例:

d.run(function() {
    process.nextTick(function() {
        // do stuff
    });
});

在这种情况下,缺陷不在摩卡。

NodeJS域的证明没有捕获try / catch中的同步错误:https://gist.github.com/owenallenaz/7141699

答案 1 :(得分:4)

nodejs域确实可以捕获同步错误

参见这个简单的测试用例

var domain = require("domain");
var d = domain.create();

d.on("error", function() {
    console.log("domain caught");
});


d.run(function() {
    throw new Error("foo");
});


// result: domain caught

编辑:自写这个答案以来,我写了一篇博客文章,描述域名的内容并尝试捕获,以及是否可以使用域名作为try catch的批发替代品。它总结了这里讨论的大部分内容。

http://www.lighthouselogic.com/node-domains-as-a-replacement-for-try-catch/

原始回答:

实际上Mocha存在问题。

我写了以下测试函数:

function error(callback){
     var d = domain.create().on('error', function(err){
        console.log("Caught Error in Domain Handler")
        return callback(err);
    });
    d.enter();
    throw new Error("TestError");
    d.exit();
}

然后我写了一个没有mocha的简单测试:

error(function(err){
    if(err)
    {
        console.log("Error was returned");
    }else
    {
        console.log("Error was not returned")
    }
})

我收到的输出是:

Caught Error in Domain Handler
Error was returned

当我使用Mocha测试时:

describe('Domain Tests', function(){
    it('Should return an error when testing', function(done){
        error(function(err){
            if(err)
            {
                console.log("Error was returned");
            }else
            {
                console.log("Error was not returned")
            }
            return done();
        })
    });
});

我收到了以下输出:

․

  0 passing (4ms)
  1 failing

  1) Domain Tests Should return an error when testing:
     Error: TestError
      at error (/Users/bensudbury/Documents/node_projects/testMochaDomains/test.js:9:11)
      at Context.<anonymous> (/Users/bensudbury/Documents/node_projects/testMochaDomains/testMocha.js:6:3)
      at Test.Runnable.run (/usr/local/share/npm/lib/node_modules/mocha/lib/runnable.js:194:15)
      at Runner.runTest (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:358:10)
      at /usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:404:12
      at next (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:284:14)
      at /usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:293:7
      at next (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:237:23)
      at Object._onImmediate (/usr/local/share/npm/lib/node_modules/mocha/lib/runner.js:261:5)
      at processImmediate [as _immediateCallback] (timers.js:330:15)

如您所见:域错误处理程序已被短路。

此问题似乎与以下问题有关:

https://github.com/visionmedia/mocha/issues/513

虽然Node问题已经关闭,但mocha中的问题仍然存在。

https://gist.github.com/mcollina/4443963中建议的解决方法在这种情况下无法解决问题。

我挖掘了Mocha的代码并发现问题的发生是因为mocha将测试包装在try catch块中。这意味着异常被捕获并且永远不会发送到uncaughtException或_fatalException处理程序,具体取决于您使用的节点的版本。

您的解决方法很好,但 nodejs域确实可以捕获同步错误,因此我不会更改您的代码,而是更改您的测试。您的新测试应如下所示:

describe("test", function() {
    it("should succeed", function(done) {
        process.nextTick(function(){
            var foo = require("./foo.js");
            foo(function() {
                console.log("done");
                done();
            });
        })      
    });
});

我没有测试过这段代码,但我的示例的类似代码正常运行:

it('Should return an error when testing', function(done){   
    process.nextTick(function(){
        error(function(err){
            if(err)
            {
                console.log("Error was returned");
            }else
            {
                console.log("Error was not returned")
            }
            return done();
        });
    })
});

我在Mocha的问题结尾添加了评论,看看是否可以解决:

https://github.com/visionmedia/mocha/issues/513