首页 > 解决方案 > 笑话:在 Promise 中测试递归调用

问题描述

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

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

我可以看到呼叫被正确记录。只有当测试完成时数字是错误的。

感谢您的任何帮助!

标签: typescriptunit-testingmockingjestjs

解决方案


解决方案 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()有机会运行之前运行和失败。


推荐阅读