You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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方式需要匹配嵌套结构:

  1. 创建UtilsService的Spy对象
    先Mock UtilsService,包含userBelongsTo方法:

    const mockUtilsService = jasmine.createSpyObj('UtilsService', ['userBelongsTo']);
    
  2. 创建ApiService的Spy对象并关联utilsService
    再Mock ApiService,给它添加utilsService属性并指向上面的mockUtilsService:

    const mockApiService = jasmine.createSpyObj('ApiService', []);
    mockApiService.utilsService = mockUtilsService;
    
  3. 设置正确的返回值
    原userBelongsTo方法返回布尔值,不是Observable,直接设置true或false即可:

    mockUtilsService.userBelongsTo.and.returnValue(true); // 根据测试场景切换true/false
    
  4. 在测试模块中提供Mock服务
    在TestBed.configureTestingModule中替换真实服务:

    beforeEach(async () => {
      await TestBed.configureTestingModule({
        declarations: [CashFlowSalariesComponent],
        providers: [
          { provide: ApiService, useValue: mockApiService }
        ]
      }).compileComponents();
    });
    

这样Mock的结构就和真实服务的层级完全匹配,HTML中的调用就能正常找到对应的方法了。

内容的提问来源于stack exchange,提问作者Jesus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:10:28