Angular单元测试嵌套服务Mock返回undefined问题求助
在Angular项目中用Karma + Jasmine做组件单元测试时,HTML通过*ngIf调用服务方法:
<div class="row" *ngIf="apiService.utilsService.userBelongsTo('operations')"></div>
组件构造函数注入了ApiService:
export class CashFlowSalariesComponent implements OnInit, OnChanges { constructor( public apiService: ApiService, ) {} }
ApiService内部通过Injector获取UtilsService,UtilsService包含userBelongsTo方法:
@Injectable() export class ApiService { public utilsService: UtilsService; constructor(private injector: Injector) { this.utilsService = injector.get(UtilsService); } }
userBelongsTo(groupName: string) { return this.groups.split(',').reduce((c, g) => c || g.toUpperCase() == groupName.toUpperCase(), false); }
尝试在spec.ts中Mock ApiService:
mockApiService = jasmine.createSpyObj(['userBelongsTo'])
并设置返回值:
mockApiService.userBelongsTo.and.returnValue(of('operations'))
但调试时出现错误:
Cannot read properties of undefined (reading 'userBelongsTo')
问题出在Mock的结构不符合真实服务的层级——HTML中调用的是apiService.utilsService.userBelongsTo,但你直接把userBelongsTo挂在了mockApiService上,导致mockApiService.utilsService为undefined,自然找不到目标方法。正确的Mock方式需要匹配嵌套结构:
创建
UtilsService的Spy对象
先MockUtilsService,包含userBelongsTo方法:const mockUtilsService = jasmine.createSpyObj('UtilsService', ['userBelongsTo']);创建
ApiService的Spy对象并关联utilsService
再MockApiService,给它添加utilsService属性并指向上面的mockUtilsService:const mockApiService = jasmine.createSpyObj('ApiService', []); mockApiService.utilsService = mockUtilsService;设置正确的返回值
原userBelongsTo方法返回布尔值,不是Observable,直接设置true或false即可:mockUtilsService.userBelongsTo.and.returnValue(true); // 根据测试场景切换true/false在测试模块中提供Mock服务
在TestBed.configureTestingModule中替换真实服务:beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [CashFlowSalariesComponent], providers: [ { provide: ApiService, useValue: mockApiService } ] }).compileComponents(); });
这样Mock的结构就和真实服务的层级完全匹配,HTML中的调用就能正常找到对应的方法了。
内容的提问来源于stack exchange,提问作者Jesus

