如何使用JEST测试Prom递归

时间:2019-05-14 00:01:03

标签: javascript typescript jestjs

我用JEST编写了一个测试。 我不知道如何在JEST中测试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. 始终传递一个解决承诺,并且重试功能在首次执行时得到解决
  2. 传递解决方案以在第三次运行时解决,重试功能在第三次运行时得到解决

我想用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递归处理。

2 个答案:

答案 0 :(得分:2)

也许您的retry任务花费了太多时间(例如:4,9s),那么您没有足够的时间来进行下一个测试用例。

您可以使用timeout来增加JEST的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);
  });

答案 1 :(得分:1)

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

await替换resolve()可能会有所帮助(然后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);