You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加retry(2)后,如何用HttpClientTestingModule测试HTTP请求错误响应

解决HttpClientTestingModule测试带retry(2)的HTTP请求报错问题

嘿,我完全懂你遇到的困扰——给HTTP请求加上retry(2)操作符后,测试就抛出了"Expected no open requests, found 1"的错误。这是因为retry(2)会在请求失败时自动重试两次,也就是说你的get()方法总共会发起3次请求(原始请求+2次重试),而你原来的测试只处理了1次,剩下的请求没被HttpTestingController预期到,所以就触发了报错。

下面是具体的解决方法,我会针对两种常见测试场景给出示例:


测试场景1:三次请求全部失败(最终进入catchError)

这个场景用来验证retry逻辑正常执行,三次请求都失败后最终捕获错误:

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { Service } from './service';

describe('Service', () => {
  let service: Service;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [Service]
    });
    service = TestBed.inject(Service);
    httpMock = TestBed.inject(HttpTestingController);
  });

  afterEach(() => {
    // 验证所有请求都被处理完毕,避免遗漏
    httpMock.verify();
  });

  it('should retry failed GET request exactly 2 times before failing', () => {
    service.get().subscribe({
      error: (error) => {
        // 确认最终捕获到的是500错误
        expect(error.status).toBe(500);
      }
    });

    // 处理第一次请求:返回500错误
    const firstRequest = httpMock.expectOne('URL');
    firstRequest.flush('Server Error', { status: 500, statusText: 'Internal Server Error' });

    // 处理第一次重试:同样返回500错误
    const secondRequest = httpMock.expectOne('URL');
    secondRequest.flush('Server Error', { status: 500, statusText: 'Internal Server Error' });

    // 处理第二次重试:还是返回500错误
    const thirdRequest = httpMock.expectOne('URL');
    thirdRequest.flush('Server Error', { status: 500, statusText: 'Internal Server Error' });
  });
});

测试场景2:前两次失败,第三次重试成功

这个场景模拟服务在两次失败后,第三次请求成功的情况:

it('should succeed after 2 failed retries', () => {
  let receivedResponse: any;

  service.get().subscribe({
    next: (response) => {
      receivedResponse = response;
    }
  });

  // 第一次请求失败
  const firstReq = httpMock.expectOne('URL');
  firstReq.flush('Initial Error', { status: 500, statusText: 'Server Down' });

  // 第一次重试失败
  const secondReq = httpMock.expectOne('URL');
  secondReq.flush('Retry Error', { status: 500, statusText: 'Still Down' });

  // 第二次重试成功
  const thirdReq = httpMock.expectOne('URL');
  thirdReq.flush({ data: 'Success!' });

  // 确认最终收到的是成功响应
  expect(receivedResponse).toEqual({ data: 'Success!' });
});

关键要点说明

  • httpMock.expectOne('URL')每次调用都会匹配下一个未被处理的、指向该URL的请求。因为retry(2)会发起3次请求,所以我们需要调用3次expectOne来处理每一次请求。
  • 一定要在afterEach里调用httpMock.verify(),它会检查是否有未被预期的请求存在,确保你的测试覆盖了所有可能的请求。
  • 你之前的测试报错,核心原因就是只处理了1次请求,剩下的2次重试请求没有被HttpTestingController处理,导致它认为还有未完成的请求。

内容的提问来源于stack exchange,提问作者Kim Kern

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:35:19