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
相关产品推荐
相关产品推荐

