如何使用Jasmine测试返回HttpClient Observable的组件函数,排查返回undefined问题
问题原因
- 核心原因是你创建的
jasmine间谍对象没有给getEasy、getMedium方法设置返回值:默认情况下jasmine.createSpyObj生成的间谍方法调用后只会返回undefined,和你实际业务中ApiService方法返回HttpClientObservable的逻辑不符,所以最终得到的adviceEndpoint是undefined。 - 次要注意点:组件定义的
getProperties方法声明了入参data,你测试调用时没有传参,不过当前代码逻辑没有用到data参数,所以不影响本次结果,后续如果用到该参数需要注意传值。
修复方案
1. 给间谍方法设置模拟返回值
你需要主动给间谍方法指定返回值,模拟真实HttpClient方法返回的Observable,需要用到RxJS的of方法快速生成模拟Observable。
修改beforeEach中apiServiceSpy的定义部分:
// 先导入of import { of } from 'rxjs'; // 在创建spy后添加返回值设置 const apiServiceSpy = jasmine.createSpyObj('ApiService', ["getEasy", "getMedium"]); // 模拟getEasy返回的Observable apiServiceSpy.getEasy.and.returnValue(of({ // 这里可以填你业务中接口返回的模拟数据 id: 1, content: 'easy难度的建议' })); // 模拟getMedium返回的Observable apiServiceSpy.getMedium.and.returnValue(of({ id: 2, content: 'medium难度的建议' }));
2. 完善测试用例的断言逻辑
你可以根据测试需求增加两类断言:一是验证方法调用符合预期,二是验证返回的Observable内容正确:
it("should return correct properties for easy type", () => { const apiService = TestBed.inject(ApiService); const properties = component.getProperties(); // 断言返回的adviceEndpoint不是undefined expect(properties.adviceEndpoint).toBeDefined(); // 断言正确调用了getEasy方法,没有调用getMedium expect(apiService.getEasy).toHaveBeenCalled(); expect(apiService.getMedium).not.toHaveBeenCalled(); // 如果需要验证Observable返回的内容,订阅后断言即可 properties.adviceEndpoint.subscribe(res => { expect(res.content).toBe('easy难度的建议'); }); });
3. 多场景测试拓展
如果要测试type为medium的场景,只需要在对应测试用例里修改ActivatedRoute的模拟值,再调用方法即可:
it("should return correct properties for medium type", () => { const apiService = TestBed.inject(ApiService); // 修改路由参数为medium route.snapshot.paramMap = convertToParamMap({ type: 'medium' }); const properties = component.getProperties(); expect(properties.adviceEndpoint).toBeDefined(); expect(apiService.getMedium).toHaveBeenCalled(); });
内容的提问来源于stack exchange,提问作者Timuçin Çiçek
相关产品推荐
相关产品推荐

