代码之家  ›  专栏  ›  技术社区  ›  Flame_Phoenix

用mocha和sinon测试插座

  •  1
  • Flame_Phoenix  · 技术社区  · 8 年前

    出身背景

    const myFun = socket => {
    
        socket.emit("first", "hello World!");
    
        setTimeout(() => {
            socket.emit("second", "hello Moon!");
        }, 1000);
    
        setTimeout(() => {
            socket.emit("third", "hello Mars? Venus? I dunno...");
        }, 2000);
    };
    

    因为我将套接字依赖注入到使用它的函数中,所以只需向其传递一个假套接字,并测试它是否被调用以及使用哪些参数(例如,使用sinon.js)即可。

    我不知道考试什么时候结束 . 因为 myFun 不会回复任何承诺,也不会回复任何我不知道如何告诉摩卡的信息,我已经发送了所有我想要的信息,测试应该结束。

    目前,我正在使用以下代码:

    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);
                }
            }, 3000);
            //we wait 3 seconds because it should be more than enough for all messages to be delivered
        });
    
    });
    

    我正在使用 setTimeout try catch 测试代码,这真的很可怕。

    问题

    • 我如何重做我的测试,使我不依赖计时器?
    3 回复  |  直到 8 年前
        1
  •  1
  •   robertklep    8 年前

    您可以使用 fake timers

    describe("myFun", () => {
      const fakeSocket = { emit: sinon.spy() }
    
      beforeEach(() => {
        this.clock = sinon.useFakeTimers();
      });
    
      afterEach(() => {
        fakeSocket.emit.reset();
        this.clock.restore();
      });
    
      it('emit first message', () => {
        myFun(fakeSocket);
        expect(fakeSocket.emit).to.have.been.calledOnce;
      });
    
      it('emit second message after 1000ms', () => {
        myFun(fakeSocket);
        this.clock.tick(1000);
        expect(fakeSocket.emit).to.have.been.calledTwice;
      });
    
      it('emit third message after 2000ms', () => {
        myFun(fakeSocket);
        this.clock.tick(2000);
        expect(fakeSocket.emit).to.have.been.calledThrice;
      });
    });
    

    或者根本没有任何计时器(制作 setTimeout 同步调用传递的回调):

    describe("myFun", () => {
      const fakeSocket = { emit: sinon.spy() }
      const stub       = sinon.stub(global, 'setTimeout').callsArg(0);
    
      after(() => {
        stub.restore();
      });
    
      it('should emit three messages', () => {
        myFun(fakeSocket);
        expect(fakeSocket.emit).to.have.been.calledThrice;
      });
    });
    
        2
  •  0
  •   Dave Irvine    8 年前

    最后一条消息是哪条?现在你发出三条信息,但是如果 myFun 我的乐趣 在涉及异步时完成,除非您告诉它。

    也许你应该 socket.emit('done')

        3
  •  0
  •   Owen C. Jones    8 年前

    你需要注意的是 Sinon fake timers

    Sinon中的假计时器允许您控制内置计时函数的输出,如 Date 建造商,以及 setTimeout setInterval

    中的基本用法 mocha 可能是这样的:

    let clock;
    beforeEach(() => {
        clock = sinon.useFakeTimers();
    });
    
    it ('should do a thing', () => {
        //assertion
    });
    
    it ('should a thing 1000 ms later'), () => {
        clock.tick(1000);
        //assertion
    });
    
    afterEach(() => {
        clock.restore();
    });