使用mocha和sinon测试异步函数

时间:2017-10-04 08:38:37

标签: javascript node.js sockets mocha sinon

背景

我是一个通过套接字发出消息的小函数,我试图用mocha和sinon来测试它:

const myFun = socket => {

    socket.emit("first", "hello World!");

    //some random amount of time passes
    socket.emit("second", "hello Moon!");

    //other random amount of time passes
    socket.emit("third", "hello Mars? Venus? I dunno...");
};

使用sinon我可以传递给我的函数一个fakeSocket:

const fakeSocket = {
    emit: sinon.spy()
};

检查我是否发出了消息。

问题

这里的问题是我不知道我的测试何时结束。因为myFun没有返回承诺而且我没有最终的消息,所以我不知道如何告诉mocha我已经发送了我想要的所有消息并且测试应该端。

测试

const chai = require("chai");
const expect = chai.expect;
const chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
const sinon = require("sinon");
const sinonChai = require("sinon-chai");
chai.use(sinonChai);

describe("myFun", () => {

    const fakeSocket = {
            emit: sinon.spy()
        };

    it("receive first message", done => {

        myFun(fakeSocket);

        setTimeout(() => {
            try{
                expect(fakeSocket.emit).to.have.been.calledThrice;
                done();
            }catch(err){
                done(err);
            }
        }, 1000);
        //1 seconds should be more than enough to let the test complete.
    });

});

我正在使用setTimeouttry catch来测试代码,这实在是太可怕了。

问题

  • 如何重新制作测试,以便我不依赖setTimeout

1 个答案:

答案 0 :(得分:1)

如果您知道特定消息总是最后设置,则可以指示Sinon在发出该消息时调用函数。该函数可以是Mocha的异步测试回调函数:

describe("myFun", function() {
  // Extend timeout and "slow test" values.
  this.timeout(3000).slow(10000);

  const fakeSocket = { emit: sinon.stub() }

  it('should emit a certain final message', done => {
    fakeSocket.emit.withArgs('third', 'hello Mars? Venus? I dunno...')
                   .callsFake(() => done());
    myFun(fakeSocket);
  });
});

因此,如果使用参数socket.emit()调用'third', 'hello Mars?...',Sinon将调用一个调用done回调的函数,向Mocha发出测试已完成的信号。

由于某种原因,当没有发出特定消息时,done永远不会被调用,测试将超时(3秒后),这表明测试失败了,或者是比预期更多的时间。

如果你不知道socket.emit()的第一个参数对于最后一条消息是什么,只有消息本身,测试就变成了这个:

it('should emit a certain final message', done => {
  fakeSocket.emit.callsFake((name, msg) => {
    if (msg === 'hello Mars? Venus? I dunno...') {
      done();
    }
  });
  myFun(fakeSocket);
})