如何使用Jest在javascript中编写实现指数退避重试方法的单元测试

问题描述

尝试测试通过提取5次重试API请求的指数补偿方法,将具有以下延迟:[1 ms,10 ms,100 ms,1 s,10 s],我无法成功测试

方法

export const delay = retryCount => new Promise(resolve => setTimeout(resolve,10 ** retryCount));

/**
 * Fetching with delay when api call fails,* first 5 retries will have the following delays: [1 ms,10 ms,100 ms,1 s,10 s]
 */
export const fetchRetry = async (options,retryCount = 0,lastError = null) => {
  if (retryCount > 5) throw new Error(lastError);
  try {
    return await fetch(options);
  } catch (error) {
    await delay(retryCount);
    return fetchRetry(options,retryCount + 1,error);
  }
};

测试

import fetchMock from 'jest-fetch-mock';

import { delay,fetchRetry } from './retry';

// This can be set up globally if needed
fetchMock.enableMocks();

beforeEach(() => {
  fetch.resetMocks();
});

describe('fetchWithExponentialBackoffRetry',() => {
  it('fetch is called once when response is 200',done => {
    fetch.mockResponSEOnce(
      JSON.stringify({
        success: true,message: 'OK',code: 200,data: 'c86e795f-fe70-49be-a8fc-6876135ab109',}),);

    setTimeout(function() {
      fetchRetry({
        inventory_type_id: 2,advertiser_id: 2315,file: null,});
      expect(fetch).toHaveBeenCalledTimes(1);
      done();
    },0);
  });

  it('fetch is called 5 times when response is returns failure',done => {
    fetch.mockReject(() => Promise.reject(new Error('Rejected')));

    setTimeout(function() {
      fetchRetry({
        inventory_type_id: 2,});
      expect(fetch).toHaveBeenCalledTimes(5);
      done();
    },100000);
  });
});

我遇到以下错误

console.error node_modules / jsdom / lib / jsdom / virtual-console.js:29 错误错误:连接ECONNREFUSED 127.0.0.1:8

我认为必须这样做delay方法,我必须以某种方式将setTimeout合并到我的测试中,现在确定如何在此处进行模拟。我会很感激的。

解决方法

您正在测试异步函数的结果,因此也需要使测试也异步-您不是这样做的-即您不是在等待fetchRetry,因此只是在调用{{1 }}同步。

认为该错误是由于此处使用done()引起的。这看起来像是一个竞态条件错误,很难在不调试的情况下确定,但是从阅读代码来看,问题似乎是您正在用setTimeout来模拟fetch,但是由于测试代码是同步运行的你有...

jest-fetch-mock

...这可能是在首先运行的测试中进行调用之前取消beforeEach(() => { fetch.resetMocks(); }); 模拟的设置,因此它实际上是在调用您的API-因此出错。

使测试异步非常简单-docs are here-使用async / await甚至更干净,因为您实际上不需要使用fetch-测试只是在promise解析后完成(或拒绝)。

基本上,您的测试代码将基本相同,不同的是,您将done调用await,就像这样:

fetchRetry