node.js如何获得更好的使用摩卡asynchronoustesting的错误消息

我的node.js mocha套件中的典型testing如下所示:

it("; client should do something", function(done) { var doneFn = function(args) { // run a bunch of asserts on args client.events.removeListener(client.events.someEvent, userMuteFn); done(); } client.events.on(someEvent, doneFn); client.triggerEvent(); }); 

这里的问题是,如果client.triggerEvent()没有做正确的事情,或者如果服务器中断,永远不会调用someEvent ,那么done()将永远不会被调用。 这为以前没有使用过testing套件的人留下了一个模棱两可的错误,如:

Error: timeout of 10500ms exceeded. Ensure the done() callback is being called in this test.

我的问题是,有没有办法重写这些testing,无论是与摩卡或除了另一个库,这使得asynchronous工作更容易遵循。 我希望能够输出如下内容:

the callback doneFn() was never invoked after clients.event.on(...) was invoked

或者可能类似的东西。

我不确定使用诸如承诺之类的东西是否会对此有所帮助。 asynchronous/callbacktypes代码更有意义的错误消息将是一件好事。 如果这意味着从callback/asynchronous移动到另一个工作stream,那么我也可以。

什么是一些解决scheme?

当你得到一个超时错误而不是一个更精确的错误时, 首先要做的是检查你的代码是否吞下exception,并且不会吞下承诺拒绝。 摩卡旨在检测这些在你的testing。 除非你在自己的虚拟机上运行testing代码或者操作域 ,否则Mocha会检测到这样的错误,但是如果你的代码吞下了它们,那么Mocha就没有办法做到这一点。

这就是说,摩卡将无法告诉你, done没有被调用,因为你的实现有一个逻辑错误,导致它无法调用callback。

以下是在检测失败后, sinon可以做的事情。 让我强调这是一个概念certificate 。 如果我想持续使用它,我会开发一个合适的库。

 var sinon = require("sinon"); var assert = require("assert"); // MyEmitter is just some code to test, created for the purpose of // illustration. var MyEmitter = require("./MyEmitter"); var emitter = new MyEmitter(); var postMortem; beforeEach(function () { postMortem = { calledOnce: [] }; }); afterEach(function () { // We perform the post mortem only if the test failed to run properly. if (this.currentTest.state === "failed") { postMortem.calledOnce.forEach(function (fn) { if (!fn.calledOnce) { // I'm not raising an exception here because it would cause further // tests to be skipped by Mocha. Raising an exception in a hook is // interpreted as "the test suite is broken" rather than "a test // failed". console.log("was not called once"); } }); } }); it("client should do something", function(done) { var doneFn = function(args) { // If you change this to false Mocha will give you a useful error. This is // *not* due to the use of sinon. It is wholly due to the fact that // `MyEmitter` does not swallow exceptions. assert(true); done(); }; // We create and register our spy so that we can conduct a post mortem if the // test fails. var spy = sinon.spy(doneFn); postMortem.calledOnce.push(spy); emitter.on("foo", spy); emitter.triggerEvent("foo"); }); 

这里是MyEmitter.js的代码:

 var EventEmitter = require("events"); function MyEmitter() { EventEmitter.call(this); } MyEmitter.prototype = Object.create(EventEmitter.prototype); MyEmitter.prototype.constructor = MyEmitter; MyEmitter.prototype.triggerEvent = function (event) { setTimeout(this.emit.bind(this, event), 1000); }; module.exports = MyEmitter; 

除了someEvent之外,还应该监听uncaughtException事件。 这样你就可以发现客户端发生的错误,并且这些错误会显示在你的testing报告中。

  it("; client should do something", function(done) { var doneFn = function(args) { // run a bunch of asserts on args client.events.removeListener(client.events.someEvent, userMuteFn); done(); } var failedFn = function(err) { client.events.removeListener('uncaughtException', failedFn); // propagate client error done(err); } client.events.on(someEvent, doneFn); client.events.on('uncaughtException', failedFn); client.triggerEvent(); }); 

PS如果client是subprocess,您还应该监听exit事件,如果subprocess死亡,将会触发该事件。