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

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);
    });
});

关键修改点

  1. 移除手动实例化:不再使用new ConcretePage(),改用TestBed.createComponent()创建组件实例,让Angular处理依赖注入。
  2. 调整测试配置:抽象组件KycBasePageComponent不需要在declarations中声明,只需要声明具体的实现类ConcretePage。
  3. 触发组件初始化:调用fixture.detectChanges()触发组件的初始化生命周期,确保构造函数执行完成,inject()调用成功。
  4. 移除多余的inject()辅助函数:测试函数不再需要inject(),因为组件实例已经通过TestBed注入了所需依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:57:39