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

Angular Jasmine单元测试spec中import与provider配置及报错排查

Angular单元测试TestBed配置规则

不用死记配置项,按下面的规则区分就行:

  • 放到imports数组的内容:带@NgModule装饰器的模块类。就是你写业务代码时,在@NgModule({imports: []})里引入的那些模块,比如ReactiveFormsModule、RouterTestingModule、第三方库的功能模块都放这。
  • 放到providers数组的内容:通过依赖注入获取的服务/令牌。就是你写在类构造函数里、要Angular注入器帮你创建实例的对象,这些内容你可以传真实服务类,也可以传自定义的mock测试对象,单元测试优先用mock隔离外部依赖。
  • 不需要进TestBed配置的内容:文件顶部import的纯工具函数、TypeScript类型、常量,这些是代码直接调用的,不走Angular依赖注入系统,完全不需要配置。你之前spec文件里引入的getApp、signOut、addDoc、collection、getFirestore都属于这类,属于多余导入。
报错原因

你的AuthService构造函数声明了三个需要注入的依赖:

  1. Auth(来自@angular/fire/auth):测试模块没有提供该依赖的实现,这也是当前报错的直接原因
  2. Router:你引入了RouterTestingModule,该模块已经内置了Router的测试实现,这部分配置正确
  3. AlertController(来自@ionic/angular):测试模块同样没有提供该依赖的实现,解决完Auth的报错后会继续报这个依赖缺失的错误

另外你的服务代码里有个不利于测试的写法:类属性直接初始化userCollection = collection(getFirestore(getApp()), 'users'),这行代码在服务实例化时会直接执行,调用Firebase全局方法,不走依赖注入,哪怕你provider配置全了,这行还是会尝试连接真实Firebase导致测试失败,建议把Firestore相关依赖也改成构造函数注入的形式,方便测试时mock。

修复方案

单元测试要保证隔离性,不要连接真实Firebase、不要触发真实弹窗、不要执行真实路由跳转,所有外部依赖全部用mock桩对象替代,不要引入完整的第三方生产模块。修正后的spec代码如下:

import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AuthService } from './auth.service';
import { Auth } from '@angular/fire/auth';
import { AlertController } from '@ionic/angular';

describe('AuthService', () => {
  let service: AuthService;
  // 创建所有外部依赖的mock对象
  const mockAuth = jasmine.createSpyObj('Auth', []);
  const mockAlertInstance = jasmine.createSpyObj('Alert', ['present']);
  const mockAlertController = jasmine.createSpyObj('AlertController', ['create']);
  mockAlertController.create.and.resolveTo(mockAlertInstance);

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      providers: [
        AuthService,
        { provide: Auth, useValue: mockAuth },
        { provide: AlertController, useValue: mockAlertController }
      ]
    });
    service = TestBed.inject(AuthService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

其他组件的spec文件报同样错误的原因完全一致:只要组件/服务的构造函数注入了AuthService或者它依赖的Auth、AlertController等对象,但是测试模块没有提供对应依赖的实现,就会抛出NullInjectorError,按照上面的规则补全mock依赖即可。

内容的提问来源于stack exchange,提问作者D.Hodges

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:42:25