Angular单元测试调用服务时出现undefined错误排查
解决Angular单元测试中TypeError: Cannot set properties of undefined的问题
错误原因
你遇到的TypeError: Cannot set properties of undefined (setting 'userBelongsTo'),本质是因为你创建的mockCashFlowService(ApiService的模拟对象)没有初始化utilsService属性,但组件HTML里直接调用了apiService.utilsService.userBelongsTo('operations')——当你试图设置mockCashFlowService.userBelongsTo时,mockCashFlowService.utilsService本身是undefined,自然无法给它的子属性赋值。
解决方案
要正确模拟ApiService的结构,需要先创建UtilsService的模拟对象,再将其挂载到ApiService的模拟对象上,具体步骤如下:
1. 调整mock对象的创建逻辑
在测试的beforeEach中,先模拟UtilsService的userBelongsTo方法,再将这个模拟对象赋值给ApiService模拟对象的utilsService属性:
beforeEach(async(() => { data = [{ id: 1006, role: "Developer", // ...其他数据 }] // 1. 模拟UtilsService,指定需要mock的方法 const mockUtilsService = jasmine.createSpyObj('UtilsService', ['userBelongsTo']); // 设置默认返回值,根据测试场景可以后续修改 mockUtilsService.userBelongsTo.and.returnValue(true); // 2. 模拟ApiService,指定需要mock的方法(比如createTableData) mockCashFlowService = jasmine.createSpyObj('ApiService', ['createTableData']); // 3. 将模拟的UtilsService挂载到ApiService模拟对象上 mockCashFlowService.utilsService = mockUtilsService; // ...后续TestBed配置代码不变 }));
2. 在测试用例中控制返回值
如果需要在特定测试用例中修改userBelongsTo的返回结果,直接操作mockUtilsService即可,无需再修改mockCashFlowService的层级属性:
it('should set salaries data correctly', () => { // 根据测试需求设置userBelongsTo的返回值 mockUtilsService.userBelongsTo.and.returnValue(true); mockCashFlowService.createTableData.and.returnValue(of(data)); fixture.detectChanges(); expect(fixture.componentInstance.dataHeaders.length).toBe(10); })
可选优化
由于我们已经通过mockCashFlowService提供了模拟的utilsService,测试模块的providers数组中可以移除UtilsService,避免不必要的依赖注入:
providers: [{ provide: ApiService, useValue: mockCashFlowService }, UserService, ProfileService, VettingStatusService, ApplicationRoleService, SeniorityLevelService, PlacementStatusService, EducationLevelService, // 移除这里的UtilsService ShirtSizeService, // ...其他服务不变 ]
内容的提问来源于stack exchange,提问作者Jesus
相关产品推荐
相关产品推荐

