node.js如何使用mocha为异步测试获取更好的错误消息

时间:2016-06-28 18:46:48

标签: javascript node.js asynchronous mocha

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

 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()永远不会被调用。对于之前没有使用过测试套件的人来说,这会产生一个模棱两可的错误:

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

我的问题是,有没有办法重写这些测试,无论是使用mocha还是另外一个lib,都可以让这样的异步工作更容易理解。我希望能够输出如下内容:

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

或者类似的东西。

我不确定使用诸如承诺之类的东西会对此有所帮助。异步/回调类型代码更有意义的错误消息将是一件好事。如果这意味着从回调/异步转移到另一个工作流程,我也可以。“/ p>

有哪些解决方案?

2 个答案:

答案 0 :(得分:2)

当你收到超时错误而不是更准确的错误时,要做的第一件事就是检查你的代码是否不会吞下异常,并且它不会吞下承诺拒绝。 Mocha是旨在检测您的测试中的这些。除非你做一些不寻常的事情,比如在你自己的VM中运行测试代码或操纵domains,否则Mocha会检测到这样的失败,但如果你的代码吞下它们,那么Mocha就无法做到。

话虽这么说,但是Mocha不能告诉你done没有被调用,因为你的实现有一个逻辑错误导致它无法调用回调。

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

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;

答案 1 :(得分:0)

除了uncaughtException之外,您还应该收听someEvent个事件。通过这种方式,您可以捕获客户端中发生的错误,这些错误将显示在您的测试报告中。

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

P.S。如果client是子进程,您还应该监听exit事件,这将在子进程终止时触发。