如何使用JEST来测试递归函数的时间过程 [英] How to use JEST to test the time course of recursive functions

查看:421
本文介绍了如何使用JEST来测试递归函数的时间过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用JEST编写了一个测试.我不知道如何在JEST中测试Promise递归.

I write a test using JEST. I do not know how to test promise recursion in JEST.

在此测试中,执行递归的重试功能是测试的目标,直到承诺被解决为止.

In this test, the retry function that performs recursion is the target of the test until the promise is resolved.

export function retry<T>(fn: () => Promise<T>, limit: number = 5, interval: number = 1000): Promise<T> {
  return new Promise((resolve, reject) => {
    fn()
      .then(resolve)
      .catch((error) => {
        setTimeout(() => {
          // Reject if the upper limit number of retries is exceeded
          if (limit === 1) {
            reject(error);

            return;
          }
          // Performs recursive processing of callbacks for which the upper limit number of retries has not been completed
          try {
            resolve(retry(fn, limit - 1, interval));
          } catch (err) {
            reject(err);
          }
        }, interval);
      });
  });
}

对上述重试功能执行以下测试.

Perform the following test on the above retry function.

  1. retry()在第三次运行中解决.第一次,第二次和第三次分别每1000秒调用一次.

我想用JEST编写这些代码如下.

I thought it would be as follows when writing these in JEST.


jest.useFakeTimers();

describe('retry', () => {
  // Timer initialization for each test
  beforeEach(() => {
    jest.clearAllTimers();
  });
  // Initialize timer after all tests
  afterEach(() => {
    jest.clearAllTimers();
  });

  test('resolve on the third call', async () => {
    const fn = jest
      .fn()
      .mockRejectedValueOnce(new Error('Async error'))
      .mockRejectedValueOnce(new Error('Async error'))
      .mockResolvedValueOnce('resolve');

    // Test not to be called
    expect(fn).not.toBeCalled();
    // Mock function call firs execution
    await retry(fn);
    // Advance Timer for 1000 ms and execute for the second time
    jest.advanceTimersByTime(1000);
    expect(fn).toHaveBeenCalledTimes(2);
    // Advance Timer for 1000 ms and execute for the third time
    jest.advanceTimersByTime(1000);
    expect(fn).toHaveBeenCalledTimes(3);

    await expect(fn).resolves.toBe('resolve');
  });

});

结果,它失败并出现以下错误.

As a result, it failed in the following error.

● retry › resolve on the third call
Timeout - Async callback was not invoked within the 30000ms timeout specified by jest.setTimeout.Error: 

    > 16 |   test('resolve on the third call', async () => {
         |   ^
      17 |     jest.useFakeTimers();
      18 |     const fn = jest
      19 |       .fn()

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

I think that it will be manageable in the setting of JEST regarding this error. However, fundamentally, I do not know how to test promise recursive processing in JEST.

推荐答案

使用计时器很难测试您的功能.

Your function is so hard to testing with timer.

当您调用await retry(fn);时,这意味着您将等到retry返回一个值,但是setTimeout已被阻塞,直到您调用jest.advanceTimersByTime(1000); =>为止,这是主要原因,因为从未调用过jest.advanceTimersByTime(1000);

When you call await retry(fn); this mean you will wait until retry return a value, but the setTimeout has been blocked until you call jest.advanceTimersByTime(1000); => this is main reason, because jest.advanceTimersByTime(1000); never been called.

您可以看到我的示例,它可以与开玩笑的假计时器一起很好地工作.

You can see my example, it is working fine with jest's fake timers.

  test("timing", async () => {
    async function simpleTimer(callback) {
      await callback();
      setTimeout(() => {
        simpleTimer(callback);
      }, 1000);
    }

    const callback = jest.fn();
    await simpleTimer(callback); // it does not block any things
    for (let i = 0; i < 8; i++) {
      jest.advanceTimersByTime(1000); // then, this line will be execute
      await Promise.resolve(); // allow any pending jobs in the PromiseJobs queue to run
    }
    expect(callback).toHaveBeenCalledTimes(9);  // SUCCESS
  });

我认为,您可以跳过测试计时器的详细信息,只需测试一下您的逻辑即可:fn被调用了3次,最后返回"resolve"

I think, you could skip test timer detail, just test about you logic: fn has been called 3 times, finally it return "resolve"

test("resolve on the third call", async () => {
    const fn = jest
      .fn()
      .mockRejectedValueOnce(new Error("Async error"))
      .mockRejectedValueOnce(new Error("Async error"))
      .mockResolvedValueOnce("resolve");

    // expect.assertions(3);

    // Test not to be called
    expect(fn).not.toBeCalled();
    // Mock function call firs execution

    const result = await retry(fn);

    expect(result).toEqual("resolve");

    expect(fn).toHaveBeenCalledTimes(3);
  });

注意:删除所有假计时器-jest.useFakeTimers

这篇关于如何使用JEST来测试递归函数的时间过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆