Angular单元测试中Observable用例断言错误仍正常通过的问题排查
问题核心原因
你的单元测试没有正确处理异步逻辑,Jasmine默认按照同步逻辑执行测试用例:subscribe 回调需要等Observable异步返回结果才会执行,但Jasmine在执行完apiService.goToPurchases(null).subscribe(...)这行代码后就直接标记测试用例执行完成,回调里的断言代码根本没有运行,所以无论断言写的是否符合预期,测试都会显示通过。
另外你当前的测试还存在两个额外问题:
- 单元测试不应发起真实HTTP请求,需要用Angular提供的
HttpClientTestingModule拦截并Mock请求结果,否则测试可用性会依赖后端服务状态 - 断言字段拼写错误:你写的
res.shimentId少了一个字母p,正确字段名是res.shipmentId
修复方案
1. 引入测试工具,正确模拟HTTP请求
首先在测试模块的导入配置中加入HttpClientTestingModule,并注入HttpTestingController用于拦截请求。
2. 正确处理异步测试逻辑,可选两种写法
写法1:使用done回调标记异步测试结束
fdescribe('goToPurchases', () => { let httpTestingController: HttpTestingController; // 省略其他服务注入逻辑 it('should have working NavApiService', (done) => { // 传入done回调 apiService.goToPurchases(null).subscribe((res: PurchaseResponse) => { expect(res.shipmentId).toBe('not supposed to be valid!') expect(res.url).not.toBeDefined(); done(); // 回调执行完成后通知Jasmine测试结束 }); // 拦截请求返回Mock数据,主动触发回调执行 const req = httpTestingController.expectOne(`${environmentVariables.loadInsurance.apiUrl}/v1/purchases`); expect(req.request.method).toBe('POST'); req.flush({ "id": "50d4ad69-0337-4e49-8f00-5c9a152cfad0", "shipmentId": null, "userId": "41ac2d3d-b2ed-4c73-9c56-25d17a9caa7e", "url": "https://test.portal.loadsure.net/insureLoad/v2?id=TFMtREFULzIwMjEwODMxL3l6ZDVlYlJRejdrQkdKcUwxbk5l" }); }); afterEach(() => { httpTestingController.verify(); // 验证所有预期请求都已触发 }); });
写法2:使用fakeAsync+tick处理异步
it('should have working NavApiService', fakeAsync(() => { let result: PurchaseResponse | undefined; apiService.goToPurchases(null).subscribe((res: PurchaseResponse) => { result = res; }); const req = httpTestingController.expectOne(`${environmentVariables.loadInsurance.apiUrl}/v1/purchases`); req.flush({ "id": "50d4ad69-0337-4e49-8f00-5c9a152cfad0", "shipmentId": null, "userId": "41ac2d3d-b2ed-4c73-9c56-25d17a9caa7e", "url": "https://test.portal.loadsure.net/insureLoad/v2?id=TFMtREFULzIwMjEwODMxL3l6ZDVlYlJRejdrQkdKcUwxbk5l" }); tick(); // 触发所有异步回调执行 expect(result?.shipmentId).toBe('not supposed to be valid!') expect(result?.url).not.toBeDefined(); }));
修改后运行测试,回调内的断言就会正常执行,不符合预期的情况下会抛出错误。
内容的提问来源于stack exchange,提问作者Julio Rodríguez
相关产品推荐
相关产品推荐

