Angular 14不使用TestBed时单元测试inject()报错问题
问题原因
直接通过new MyComponent()实例化组件时,Angular并未建立注入上下文。虽然组件代码里是用字段初始化器调用inject(),但这个调用必须在Angular管理的注入环境中执行——手动new组件的方式完全绕开了Angular的注入机制,导致inject()找不到依赖来源,触发报错。
解决方案(无需TestBed)
方案一:改用构造函数注入(推荐)
把字段初始化器的inject()改成构造函数参数注入,这样测试时可以直接手动传入Spy对象,完全不需要依赖Angular的注入环境。
修改组件代码
export class MyComponent implements OnInit, OnDestroy { constructor( private router: Router, // 把inject的服务移到构造函数参数里 private _componentRegistryService: ComponentRegistryService ) {} // ...其他原有代码 }
修改测试代码
fdescribe('DynamicComponent', () => { let component: MyComponent; // 先创建Router的Spy对象(之前的router变量未初始化,必须补上) const routerSpy = jasmine.createSpyObj('Router', ['navigate']); const componentRegistrySpy = jasmine.createSpyObj('ComponentRegistryService', ['getComponentsByRoute']); beforeEach(() => { // 实例化时直接传入所有依赖的Spy component = new MyComponent(routerSpy, componentRegistrySpy); }); it('should create', () => { expect(component).toBeTruthy(); }); });
方案二:用EnvironmentInjector模拟注入上下文
如果不想修改组件的注入方式,可以借助Angular的EnvironmentInjector创建一个临时注入环境,让inject()能正常获取依赖。
修改测试代码
import { EnvironmentInjector } from '@angular/core'; fdescribe('DynamicComponent', () => { let component: MyComponent; const routerSpy = jasmine.createSpyObj('Router', ['navigate']); const componentRegistrySpy = jasmine.createSpyObj('ComponentRegistryService', ['getComponentsByRoute']); beforeEach(() => { // 创建包含所需依赖的注入器 const injector = EnvironmentInjector.create({ providers: [ { provide: Router, useValue: routerSpy }, { provide: ComponentRegistryService, useValue: componentRegistrySpy } ] }); // 在注入上下文里实例化组件 component = injector.runInContext(() => new MyComponent(routerSpy)); }); it('should create', () => { expect(component).toBeTruthy(); }); });
方案对比
- 方案一代码更简洁直观,测试逻辑清晰,是单元测试中最常用的方式。
- 方案二适合无法修改组件代码的场景,但需要额外维护注入器的配置。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

