开玩笑:在Promise中测试递归调用

时间:2018-08-19 09:37:17

标签: typescript unit-testing mocking jestjs

测试以下课程时遇到一些问题。

interface Connector {
   connect: () => Promise<void>;
}

class Unit {
   private connector: Connector;

   constructor(connector: Connector) {
      this.connector = connector;
   }

   public attemptConnect(iteration: number, max: number): void {
      console.log("attempt" + iteration);

      this.connector.connect()
         .then(() => {
            console.log("connected");
         })
         .catch((error) => {
            if (iteration < max) {
               this.attemptConnect(iteration + 1, max);
            }
         });
   }
}

我想测试Connector.connect()函数是否被调用了正确的时间。 我正在尝试通过开玩笑实现以下目标:

describe("Unit", () => {
   it("fails to record more than one recursion", async () => {
      const connector: Connector = {
         connect: jest.fn().mockRejectedValue(new Error("foo")),
      };
      const unit: Unit = new Unit(connector);

      await unit.attemptConnect(1, 4);

      expect((connector.connect as jest.Mock).mock.calls.length).toBe(4);
   });
});

不幸的是,Expect()调用失败,说

Error: expect(received).toBe(expected) // Object.is equality

Expected: 4
Received: 1

如果我使用调试器并观察值

(connector.connect as jest.Mock).mock.calls.length

我可以看到通话记录正确。仅当测试完成时,数字才错误。

谢谢您的帮助!

1 个答案:

答案 0 :(得分:2)

解决方案1 ​​

返回attemptConnect()中的承诺:

public attemptConnect(iteration: number, max: number): Promise<void> {
  console.log("attempt" + iteration);

  return this.connector.connect()
    .then(() => {
      console.log("connected");
    })
    .catch((error) => {
      if (iteration < max) {
        return this.attemptConnect(iteration + 1, max);
      }
    });
}

解决方案2

await中测试所需的事件循环次数:

describe("Unit", () => {
  it("fails to record more than one recursion", async () => {
    const connector: Connector = {
      connect: jest.fn().mockRejectedValue(new Error("foo")),
    };
    const unit: Unit = new Unit(connector);

    unit.attemptConnect(1, 4);

    // await enough event loop cycles for all the callbacks queued
    // by then() and catch() to run, in this case 5:
    await Promise.resolve().then().then().then().then();

    expect((connector.connect as jest.Mock).mock.calls.length).toBe(4);
  });
});

详细信息

测试正在等待attemptConnect(),但是由于它没有返回任何内容,因此await没有任何内容,并且同步测试将继续执行。在expect()then()排队的回调有机会运行之前,catch()运行并失败。