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

Angular依赖含InjectionToken服务的单元测试问题排查

解决Angular测试中InjectionToken的NullInjectorError问题

看起来你在这里走了个小弯路——其实你根本不需要在测试模块里提供KEY1和KEY2,因为你已经用mockFooService替换了真实的FooService!

问题根源

你的错误提示是找不到KEY_1的提供者,这说明测试中真实的FooService还是被注入了,而不是你定义的mock对象。虽然你在providers数组里配置了{ provide: FooService, useValue: mockFooService },但由于FooService是providedIn: 'root'的服务,有时候TestBed的默认配置不会自动覆盖root级别的提供者,导致真实服务被实例化,进而需要它的依赖KEY1和KEY2。

正确解决方案

你有两种方式可以确保mock的FooService被正确注入:

方案1:显式覆盖Root级别的提供者

使用TestBed.overrideProvider方法强制替换FooService的实例,这样能确保root级别的服务被mock对象取代:

import { TestBed, inject } from '@angular/core/testing';
import { DataService } from './data.service';
import { FooService } from './foo.service';

describe('DataService', () => {
  let mockFooService: jasmine.SpyObj<FooService>;

  beforeEach(() => {
    // 创建mock对象,指定要spy的方法
    mockFooService = jasmine.createSpyObj(FooService, ['getActiveFoo']);

    TestBed.configureTestingModule({
      providers: [DataService]
    })
    // 强制覆盖FooService的提供者
    .overrideProvider(FooService, { useValue: mockFooService });
  });

  it('should be created', inject([DataService], (service: DataService) => {
    expect(service).toBeTruthy();
  }));
});

方案2:确保mock提供者优先级高于Root服务

如果你更喜欢在configureTestingModule的providers数组里配置,也可以调整写法,确保mock对象的优先级:

import { TestBed, inject } from '@angular/core/testing';
import { DataService } from './data.service';
import { FooService } from './foo.service';

describe('DataService', () => {
  let mockFooService: jasmine.SpyObj<FooService>;

  beforeEach(() => {
    mockFooService = jasmine.createSpyObj(['getActiveFoo']);

    TestBed.configureTestingModule({
      providers: [
        DataService,
        // 明确指定替换FooService的实例
        { provide: FooService, useValue: mockFooService }
        // 不需要再提供KEY1和KEY2!
      ]
    });
  });

  it('should be created', inject([DataService], (service: DataService) => {
    expect(service).toBeTruthy();
  }));
});

如果确实需要测试真实的FooService

如果你出于某些原因必须使用真实的FooService而不是mock,那你之前提供InjectionToken的方式是正确的——只要确保KEY1和KEY2的提供者和FooService一起配置:

TestBed.configureTestingModule({
  providers: [
    DataService,
    FooService,
    { provide: KEY1, useValue: 'abc' },
    { provide: KEY2, useValue: '123' }
  ]
});

但这种情况下你需要维护FooService的所有依赖,不如mock来得简洁,毕竟你测试的是DataService,不是FooService。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:59:41