首页 > 解决方案 > 如何在嵌套 HttpService 上用玩笑测试 retryWhen

问题描述

我的 NestJS 项目中有以下方法:

getAccessToken(): Observable < string > {
  return this.httpService.post(`${url}/oauth2/token`, params).pipe(
    retryWhen((errors) =>
      errors.pipe(
        delay(1000),
        take(5),
        (e) =>
          concat(
            e,
            throwError(
              `Error retrieving access token. Tried 5 times.`
            )
          )
      )
    ),
    catchError((err) => {
      this.loggerService.error(err);
      throw err;
    }),
    map((res) => res.data),
    map((data) => data.access_token)
  );
}

上面的代码将调用 API。成功则返回access_token,失败最多尝试5次,5次不成功则抛出异常。

现在我想写3个单元测试,

  1. 当 API 没有抛出错误并返回访问令牌时成功

  2. 失败6次

  3. 失败 2 次并返回访问令牌

测试1:

it('should return access_token', async () => {
  const response: AxiosResponse = {
    data: {
      access_token: 'token1'
    },
    status: 200,
    statusText: 'OK',
    headers: {},
    config: {}
  };

  const post = jest
    .spyOn(httpService, 'post')
    .mockImplementationOnce(() => of(response));

  try {
    const token = await service.getAccessToken().toPromise();
    expect(token).toBe('token1');
  } catch (err) {
    expect(true).toBeFalsy();
  }
});

测试 2:

it('should retry and fails', async () => {
  const err: AxiosError = {
    config: {},
    code: '500',
    name: '',
    message: '',
    response: {
      data: {},
      status: 500,
      statusText: '',
      headers: {},
      config: {}
    },
    isAxiosError: true,
    toJSON: () => null
  };

  const post = jest
    .spyOn(httpService, 'post')
    .mockImplementationOnce(() => throwError(err));

  try {
    await service.getAccessToken().toPromise();
    expect(true).toBeFalsy();
  } catch (err) {
    expect(err).toBe(
      'Error retrieving access token. Tried 5 times.'
    );
  }
});

但是,我不知道如何为第 3 次编写测试。

标签: unit-testingaxiosjestjsnestjs

解决方案


我找到了解决方案,以防其他人遇到同样的问题

    it('should retry and return access token', async () => {
        const response: AxiosResponse = {
            data: {
                access_token: 'token1'
            },
            status: 200,
            statusText: 'OK',
            headers: {},
            config: {}
        };

        const err: AxiosError = {
            config: {},
            code: '500',
            name: '',
            message: '',
            response: {
                data: {},
                status: 500,
                statusText: '',
                headers: {},
                config: {}
            },
            isAxiosError: true,
            toJSON: () => null
        };

        let retried = 0;

        const post = jest
            .spyOn(httpService, 'post')
            .mockImplementationOnce(() => {
                return new Observable((s) => {
                    if (retried <= 1) {
                        retried += 1;
                        s.error(err);
                    } else {
                        s.next(response);
                        s.complete()
                    }
                });
            });

        try {
            const token = await service.getAccessToken().toPromise();
            expect(token).toBe('token1');
        } catch (err) {
            expect(true).toBeFalsy();
        }

        expect(post).toHaveBeenCalled();
        expect(post).toHaveBeenCalledTimes(1);
    });

推荐阅读