我试图了解Mocha的异步代码(http://mochajs.org/#getting-started)是如何工作的。
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(function(err) {
if (err) throw err;
done();
});
});
});
});
我想知道Mocha如何决定测试在幕后是成功还是失败。
从上面的代码我可以理解,异步的user.save()
会立即返回。因此,在执行it()
之后,Mocha不会决定测试是成功还是失败。当user.save()
最终成功呼叫done()
时,摩卡会认为这是一次成功的测试。
我无法理解摩卡在上述情况下如何了解测试失败。比如,user.save()
使用err
参数集调用其回调,然后回调引发错误。在这种情况下,没有调用Mocha的函数。那么Mocha如何知道回调中发生错误?
答案 0 :(得分:7)
Mocha能够检测阻止调用回调或返回promise的失败,因为它使用process.on('uncaughtException', ...);
来检测未捕获的异常。由于它以串行方式运行所有测试,因此它始终知道未捕获的异常属于哪个测试。 (有时人们对此感到困惑:告诉Mocha一个测试是异步的并不意味着Mocha将与其他测试并行运行。它只是告诉Mocha它应该等待回调或承诺。)
除非有某些事情干预以吞下异常,否则Mocha会知道测试失败并会在检测到错误后立即报告错误。这是一个例子。由于抛出了一般异常,第一次测试失败。由于expect
检查失败,第二个失败。它也引发了一个未经处理的例外。
var chai = require("chai");
var expect = chai.expect;
it("failing test", function (done) {
setTimeout(function () {
throw new Error("pow!");
done();
}, 1000);
});
it("failing expect", function (done) {
setTimeout(function () {
expect(1).to.equal(2);
done();
}, 1000);
});
这是我的控制台上的输出:
1) failing test
2) failing expect
0 passing (2s)
2 failing
1) failing test:
Uncaught Error: pow!
at null._onTimeout (test.js:6:15)
2) failing expect:
Uncaught AssertionError: expected 1 to equal 2
+ expected - actual
-1
+2
at null._onTimeout (test.js:13:22)
堆栈跟踪指向正确的代码行。如果异常发生得更深,那么堆栈会更充分。
当Mocha无法准确报告出错时,通常是因为有干预代码吞下了引发的异常。或者当你使用promises时,问题可能是有人忘了调用方法表示是否应该完全处理promise,并且应该抛出未处理的异常。 (如何执行此操作取决于您使用的promise实现。)
答案 1 :(得分:0)
不会,这是一种耻辱。它无法知道您的回调正在执行。这是一种更简单的异步测试方法,您可以在完成时告诉测试。正如您所注意到的,缺点是异步回调中的错误将无法被检测到。没关系,Mocha挂钩到process.on('uncaughtException',...)
,如Louis所述。请注意,如果您在茉莉花then you will have the problem中使用done
而不是waitsFor
和runs
。
js-test-driver等其他框架强制给你wrap callbacks所以测试框架可以在你的回调周围设置一个try catch
(你不需要调用done)。您的测试将如下所示:
var AsynchronousTest = AsyncTestCase('User');
AsynchronousTest.prototype.testSave = function(queue) {
queue.call('Saving user', function(callbacks) {
var user = new User('Luna');
user.save(callbacks.add(function(err) {
if (err) throw err;
// Run some asserts
}));
});
};