添加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
相关产品推荐
相关产品推荐

