简体   繁体   English

使用Mocha和sinon测试异步功能

[英]Test async function with mocha and sinon

Background 背景

I am made a small function that emits messages via sockets and I am trying to test it using mocha and 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...");
};

Using sinon I can pass to my function a fakeSocket: 使用sinon我可以将一个fakeSocket传递给我的函数:

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

And check if I emit or not the messages. 并检查我是否发出消息。

Problem 问题

The problem here is that I don't know when my test ends . 这里的问题是我不知道考试何时结束 Because myFun does not return a promise and I don't have a final message I don't know how to tell mocha that I have sent all the messages I wanted and that the test should end. 因为myFun不返回承诺并且没有最终消息,所以我不知道如何告诉mocha我已经发送了所有想要的消息,并且测试应该结束。

Test 测试

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

});

I am using a setTimeout with a try catch to test the code, which honestly is quite horrible. 我正在使用带有try catchsetTimeout来测试代码,老实说这是非常可怕的。

Question

  • How do I remake my tests so I don't depend on setTimeout ? 如何重新进行测试,以使我不依赖setTimeout

If you know that a particular message is always set last, you can instruct Sinon to call a function when that message is emitted. 如果您知道总是在最后设置一条特定的消息,则可以指示Sinon在发出该消息时调用一个函数。 That function can be Mocha's callback function for asynchronous tests: 该函数可以是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);
  });
});

So if socket.emit() is called with arguments 'third', 'hello Mars?...' , Sinon will call a function that calls the done callback, signalling to Mocha that the test has completed. 因此,如果使用参数'third', 'hello Mars?...'调用socket.emit() ,则Sinon将调用一个函数,该函数调用done回调,并向Mocha表示测试已完成。

When, for some reason, that particular message isn't emitted, done never gets called and the test will time out (after 3s), which is an indication that either the test has failed, or it took more time than expected. 由于某种原因而未发出该特定消息时,将不会调用done且测试将超时(3秒后),这表明测试失败或花费了比预期更长的时间。

If you don't know what the first argument to socket.emit() is going to be for the last message, only the message itself, the test becomes this: 如果您不知道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);
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM