【问题标题】:How to test promise recursion with JEST如何使用 JEST 测试 Promise 递归
【发布时间】:2019-09-30 22:36:27
【问题描述】:

我使用 JEST 编写了一个测试。 我不知道如何在 JEST 中测试 promise 递归。

在这个测试中,执行递归的重试函数是测试的目标,直到 promise 被解决。

export function retry <T> (fn: () => Promise <T>, limit: number = 5, interval: number = 10): Promise <T> {
  return new Promise ((resolve, reject) => {
    fn ()
      .then (resolve)
      .catch ((error) => {
        setTimeout (async () => {
          // Reject if the upper limit number of retries is exceeded
          if (limit === 1) {
            reject (error);
            return;
          }
          // If it is less than the upper limit number of retries, execute callback processing recursively
          await retry (fn, limit-1, interval);
        }, interval);
      });
  });
}

对上述重试函数进行如下测试。

  1. 总是传递一个promise来解析,重试函数在第一次执行时被解析
  2. 第三次通过resolve解析,第三次解析retry函数

我以为用 JEST 写这些的时候应该是这样的。

describe ('retry', () => {
  test ('resolve on the first call', async () => {
    const fn = jest.fn (). mockResolvedValue ('resolve!');
    await retry (fn);
    expect (fn.mock.calls.length) .toBe (1);
  });

  test ('resolve on the third call', async () => {
    const fn = jest.fn ()
               .mockRejectedValueOnce (new Error ('Async error'))
               .mockRejectedValueOnce (new Error ('Async error'))
               .mockResolvedValue ('OK');
    expect (fn.mock.calls.length) .toBe (3)
  });
});

结果失败,出现如下错误。

Timeout-Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout.Error:
    > 40 | test ('resolve on the third call', async () => {
         | ^
      41 | const fn = jest
      42 | .fn ()
      43 | .mockRejectedValueOnce (new Error ('Async error'))

我认为在 JEST 的设置中关于这个错误是可以管理的。但是,从根本上说,我不知道如何在 JEST 中测试 Promise 递归处理。

【问题讨论】:

    标签: javascript typescript jestjs


    【解决方案1】:

    可能您的retry 任务执行次数过多(例如:4,9s),那么您没有足够的时间来做下一个测试用例。

    JEST 的timeout 可以增加jest.setTimeout(10000);

    Promise testing官方文档。

    我的解决方案:

    test("resolve on the third call", async () => {
        jest.setTimeout(10000);
        const fn = jest.fn()
          .mockRejectedValueOnce(new Error("Async error"))
          .mockRejectedValueOnce(new Error("Async error"))
          .mockResolvedValue("OK");
    
        // test reject value
        await expect(fn()).rejects.toEqual(new Error("Async error"));
        await expect(fn()).rejects.toEqual(new Error("Async error"));
    
        // test resolve
        const result = await fn();
        expect(result).toEqual("OK");
    
        // call time
        expect(fn).toHaveBeenCalledTimes(3);
      });
    

    【讨论】:

    【解决方案2】:

    发生超时是因为retry() 中的.catch() 处理程序在第二次尝试调用retry() 时没有调用resolve;所以第一个 retry() 返回一个永远不会解决或拒绝的承诺。

    resolve() 替换await 可能会有所帮助(并且setTimeout 中的功能不需要异步):

      .catch ((error) => {
        setTimeout (() => {
          // Reject if the upper limit number of retries is exceeded
          if (limit === 1) {
            reject (error);
            return;
          }
          // If it is less than the upper limit number of retries, execute callback processing recursively
          resolve(retry (fn, limit-1, interval));
        }, interval);
    

    【讨论】:

    猜你喜欢
    • 2020-04-21
    • 2018-03-24
    • 1970-01-01
    • 2018-07-06
    • 2020-10-19
    • 2019-10-01
    • 2019-01-25
    • 2019-02-24
    • 2015-03-30
    相关资源
    最近更新 更多