当运行利用域进行错误处理的测试时,即使库中的域处理程序应该捕获到错误,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_6u0J和https://github.com/joyent/node/issues/4375。
我感到困惑的是,所有这些讨论似乎都说明问题已在几个月前得到解决。任何人都知道这个问题的简单解决方法,或者为什么我没有看到其他人似乎相信的错误已经修复了。
我在Windows 7上运行CentOS 6.3 Vagrant VirtualBox上的节点v0.10.18和Mocha 1.13.0。
答案 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的问题结尾添加了评论,看看是否可以解决: