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

Angular测试中如何对@Inject注入的服务执行SpyOn操作mock返回值

问题根源

你当前的配置存在两个核心问题:

  1. 令牌与实例不匹配:你在providers中同时注册了字符串令牌'CategoryService'和类令牌MockCategoryService,两者对应完全独立的两个服务实例。你spy的是类令牌对应的实例,但组件实际注入的是字符串令牌对应的实例,spy自然不会生效。
  2. 执行顺序错误:你先调用了TestBed.createComponent创建组件(此时组件构造函数已经执行,若构造函数或ngOnInit中已经调用了getCategories,后续spy不会覆盖已执行的逻辑),再执行spy操作,时机太晚。

解决方法

方法1:直接获取组件使用的服务实例进行spy(修改量最小)

不需要修改providers配置,直接调整测试代码顺序,获取字符串令牌对应的实例再spy即可:

beforeEach(() => {
  // 1. 先拿到组件实际使用的字符串令牌对应的服务实例
  const categoryService = TestBed.inject<CategoryService>('CategoryService');
  // 2. 先spy方法,再创建组件
  spyOn(categoryService, 'getCategories').and.returnValue(of([{ id: 1, name: 'category01' }]));
  // 3. 最后创建组件、触发变更检测
  fixture = TestBed.createComponent(ExpensesLayoutComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});

方法2:统一令牌指向同一实例

修改providers配置,让字符串令牌和类令牌指向同一个实例,之后spy类令牌实例就会生效:

beforeEach(async () => {
  await TestBed.configureTestingModule({
    declarations: [ExpensesLayoutComponent],
    providers: [
      MockCategoryService,
      // 用useExisting指向已注册的MockCategoryService实例,两个令牌共享同一个实例
      { provide: 'CategoryService', useExisting: MockCategoryService }
    ]
  }).compileComponents();
});

beforeEach(() => {
  mockCategoryService = TestBed.inject(MockCategoryService);
  // 先spy再创建组件
  spyOn(mockCategoryService, 'getCategories').and.returnValue(of([{ id: 1, name: 'category01' }]));
  fixture = TestBed.createComponent(ExpensesLayoutComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:06:02