Angular 15使用inject()的组件测试报NG0203错误求助
Angular组件使用
inject()时测试报错NG0203的解决方法 问题背景
我正在重构组件以使用新的inject()依赖注入方式,组件运行正常,但所有测试均失败。查阅了诸多inject()在函数和服务中的使用教程,但这些方法不适用于组件。尝试所有方案后,测试套件仍报错:
NG0203: inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with
EnvironmentInjector#runInContext.
组件代码
import { Component, OnDestroy, inject } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { AppDomains } from '../models/kyc-enums.model'; @Component({ template: '' }) export abstract class KycBasePageComponent implements OnDestroy { // properties… appDomain: AppDomains; constructor() { const route = inject(ActivatedRoute); this.appDomain = route.snapshot.data.appDomain; } // methods… ngOnDestroy(): void {} }
测试文件代码
import { TestBed, inject } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; import { AppDomains } from '../models/kyc-enums.model'; import { KycSteps } from '../models/kyc-steps'; import { KycBasePageComponent } from './base-page.component'; import { IBasePage } from './base-page.interface'; class ConcretePage extends KycBasePageComponent implements IBasePage {} fdescribe('KycBasePageComponent', () => { let component: ConcretePage; let activatedRouteMock: ActivatedRoute = { snapshot: { params: { flowId: '111' }, data: { appDomain: AppDomains.Onboarding }, }, } as unknown as ActivatedRoute; beforeEach(() => { TestBed.configureTestingModule({ declarations: [ConcretePage, KycBasePageComponent], providers: [{ provide: ActivatedRoute, useValue: activatedRouteMock }], }); }); it('should extend KycBasePageComponent', inject([ActivatedRoute], () => { component = new ConcretePage(); expect(component).toBeDefined(); expect(component.appDomain).toEqual('onboarding'); })); });
问题原因
直接通过new ConcretePage()手动实例化组件时,没有在Angular的依赖注入上下文环境中执行构造函数,导致inject()方法无法获取到所需的依赖服务。inject()必须在Angular管理的注入上下文中调用,比如由TestBed创建组件实例、服务构造函数执行等场景。
解决方案
修改测试代码,通过TestBed创建组件实例,确保构造函数在Angular的注入上下文中执行:
修改后的测试代码
import { TestBed } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; import { AppDomains } from '../models/kyc-enums.model'; import { KycBasePageComponent } from './base-page.component'; import { IBasePage } from './base-page.interface'; class ConcretePage extends KycBasePageComponent implements IBasePage {} fdescribe('KycBasePageComponent', () => { let component: ConcretePage; let activatedRouteMock: ActivatedRoute = { snapshot: { params: { flowId: '111' }, data: { appDomain: AppDomains.Onboarding }, }, } as unknown as ActivatedRoute; beforeEach(() => { TestBed.configureTestingModule({ declarations: [ConcretePage], // 抽象组件无需声明,仅需声明具体实现类 providers: [{ provide: ActivatedRoute, useValue: activatedRouteMock }], }); // 通过TestBed创建组件实例,确保注入上下文生效 const fixture = TestBed.createComponent(ConcretePage); component = fixture.componentInstance; fixture.detectChanges(); // 触发组件初始化,执行构造函数 }); it('should extend KycBasePageComponent', () => { expect(component).toBeDefined(); expect(component.appDomain).toEqual(AppDomains.Onboarding); }); });
关键修改点
- 移除手动实例化:不再使用
new ConcretePage(),改用TestBed.createComponent()创建组件实例,让Angular处理依赖注入。 - 调整测试配置:抽象组件
KycBasePageComponent不需要在declarations中声明,只需要声明具体的实现类ConcretePage。 - 触发组件初始化:调用
fixture.detectChanges()触发组件的初始化生命周期,确保构造函数执行完成,inject()调用成功。 - 移除多余的
inject()辅助函数:测试函数不再需要inject(),因为组件实例已经通过TestBed注入了所需依赖。
内容的提问来源于stack exchange,提问作者brubs
相关产品推荐
相关产品推荐

