在testingmocha中的nodeJS时,域不能正确捕获错误

当运行利用域进行error handling的testing时,即使库内的域处理程序应该发现错误,Mocha仍然会抛出错误。 如果我在Mocha之外执行代码,它的function正确导致我相信问题是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它会按照需要运行,错误被域处理程序捕获,代码继续。 如果我在Mochatesting中运行相同的代码块,错误会暂停testing,并给出失败。 我相信这是因为错误是发送一个uncaughtException处理程序,或类似的东西。 另一个复杂的问题是,它在Mocha中正常工作,如果我有一个process.nextTick()函数调用,导致我相信摩卡只能处理同步错误,但对asynchronous错误工作得很好。

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

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

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

发现问题。 NodeJS域捕获同步错误,但事件继续冒泡到try / catch 。 如果你将一个domain.run()包装在try/catch那么域error handling程序AND catch将会被执行。

因此,最好的做法是在所有的domain.run()使用process.nextTick。 这在文档示例中显示,但并不像我所希望的那样明确表示。

例:

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

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

NodeJS域的certificate不会捕获try / catch中的同步错误: https : //gist.github.com/owenallenaz/7141699

nodejs域确实会捕获同步错误

看到这个简单的testing用例

 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 

编辑 :由于写这个答案,我写了一篇博客文章,描述了什么正在发生的领域,并尝试赶上,是否可以使用域作为尝试赶上批发替代品。 它总结了这里讨论的大部分内容。

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

原文答案:

其实摩卡有一个问题。

我写了下面的testing函数:

 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(); } 

然后我写了一个没有摩卡的简单testing:

 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 

当我使用摩卡testing时:

 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) 

你可以看到:域error handling程序被短路了。

这个问题似乎与以下问题有关:

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

在Node问题已经结束的时候,摩卡的问题仍然是悬而未决的。

在这种情况下, https : //gist.github.com/mcollina/4443963上build议的解决方法不能解决问题。

我挖通过摩卡的代码,发现问题的发生,因为摩卡在一个try catch块中包装testing。 这意味着这个exception被捕获,并且根据你正在使用的节点的版本,决不会发送到uncaughtException或_fatalException处理程序。

你的解决方法是好的,但nodejs域确实捕获同步错误,所以我不会改变你的代码,而是改变你的testing。 你的新testing应该是这样的:

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

我没有testing过这个代码,但是我的例子的类似代码正常工作:

 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(); }); }) }); 

我已经在摩卡的问题末尾添加了一条评论,看是否可以解决:

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