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

如何用Jest无TestBed测试含inject()的Angular组件/服务?

解决Angular中使用inject()的类的纯Jest测试问题

核心问题分析

当类通过字段初始化器直接调用inject()时(比如protected destroyRef: DestroyRef = inject(DestroyRef);),Angular强制要求该调用必须在注入上下文内执行。纯JavaScript测试环境没有Angular DI上下文支撑,直接new实例就会触发NG0203错误。

方案1:模拟inject()方法(最贴近纯JS测试)

用Jest直接mock@angular/core中的inject函数,让它返回你需要的模拟对象,彻底绕开Angular DI机制:

// 测试文件顶部先mock依赖
jest.mock('@angular/core', () => ({
  ...jest.requireActual('@angular/core'), // 保留Angular其他原生导出
  inject: jest.fn((token: any) => {
    // 根据注入的token返回对应模拟对象
    if (token.name === 'DestroyRef') {
      return {
        onDestroy: jest.fn() // 模拟DestroyRef的核心方法
      };
    }
    // 其他需要注入的token可在此扩展
    throw new Error(`未mock的token: ${token}`);
  })
}));

describe('ValueService', () => {
  let service: ValueService;

  beforeEach(() => {
    // 每次测试前重置mock状态
    (jest.mocked(require('@angular/core').inject) as jest.Mock).mockClear();
    service = new ValueService();
  });

  test('#getValue 应返回正确值', () => {
    expect(service.getValue()).toBe('real value');
    // 还能验证inject是否被正确调用
    expect(require('@angular/core').inject).toHaveBeenCalledWith(DestroyRef);
  });
});

这个方案完全脱离Angular上下文,纯JS环境即可运行,完美匹配你“无Angular上下文测试”的需求。

方案2:用runInInjectionContext创建最小注入上下文

如果不想完全mockinject,可以用Injector.create创建最小化注入器,配合runInInjectionContext提供合法的注入环境,同时注册所需的模拟提供者:

import { runInInjectionContext, Injector, DestroyRef } from '@angular/core';

describe('ValueService', () => {
  let service: ValueService;
  let mockDestroyRef: Partial<DestroyRef>;

  beforeEach(() => {
    mockDestroyRef = {
      onDestroy: jest.fn()
    };
    // 创建包含模拟提供者的注入器
    const injector = Injector.create({
      providers: [
        { provide: DestroyRef, useValue: mockDestroyRef }
      ]
    });
    // 在注入上下文内实例化服务
    runInInjectionContext(injector, () => {
      service = new ValueService();
    });
  });

  test('#getValue 应返回正确值', () => {
    expect(service.getValue()).toBe('real value');
    // 验证DestroyRef的方法是否能被正常调用
    service.someMethodThatUsesOnDestroy();
    expect(mockDestroyRef.onDestroy).toHaveBeenCalled();
  });
});

注意:Injector.create必须明确注册所有被inject()请求的token,不能用any模糊匹配——这也是你之前尝试失败的核心原因。

总结

  • 追求纯JS无Angular上下文:选方案1,直接mockinject函数
  • 需要保留部分Angular DI逻辑:选方案2,用最小注入器提供合法上下文

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:45:16