HttpTestingController匹配失败:Promise型HttpInterceptor测试问题
两个拦截器的核心差异
同步与异步触发时机的区别
- ObservableInterceptor:使用
BehaviorSubject时,它会在订阅发生时同步发出当前值(此处为true)。因此mergeMap会立即调用next.handle(request),HTTP请求同步触发,测试代码能立刻捕获到请求。 - PromiseInterceptor:通过
from(Promise.resolve(true))将Promise转为Observable后,即便Promise已resolve,from()会把Promise的结果放入微任务队列,需等当前同步代码执行完毕才会触发mergeMap中的next.handle(request)。测试中调用expectOne时,请求尚未发出,因此出现"未找到匹配请求"的错误。
实现可正常测试的Promise拦截器
拦截器本身的逻辑没有问题,只需调整测试代码的异步时序处理。Angular测试提供fakeAsync和tick()来模拟异步任务执行:
it('works with PromiseInterceptor', fakeAsync(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: PromiseInterceptor, multi: true, }, ], }); const http = TestBed.inject(HttpClient); const httpTestingController = TestBed.inject(HttpTestingController); http.get(TEST_API).subscribe(value => console.log(value)); // 触发所有待处理的微任务,让Promise回调执行完成 tick(); const request = httpTestingController.expectOne(TEST_API); expect(request.request).toBeTruthy(); // 完成请求并验证无未处理请求(测试清理步骤) request.flush({}); httpTestingController.verify(); }));
补充说明
如果业务中是调用真实异步函数(比如获取token的Promise),拦截器的写法无需修改,核心是测试时通过fakeAsync和tick()处理微任务异步场景,确保请求触发后再执行断言。
内容的提问来源于stack exchange,提问作者LucasMoody
相关产品推荐
相关产品推荐

