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

AngularFireAuth模拟问题:AuthService单元测试注入错误排查

解决AngularFireAuth注入错误及正确模拟实现

问题背景

我封装了AuthService统一处理AngularFireAuth的认证逻辑,但在执行基础的toBeTruthy断言时触发了注入错误。之前用简单模拟解决过其他组件的同类问题,但针对AngularFireAuth的复杂模拟卡壳了。

原始错误

NullInjectorError: R3InjectorError(DynamicTestModule)[AuthService -> AngularFireAuth -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]:

当前测试代码(auth.service.spec.ts)

import { TestBed } from '@angular/core/testing';

import { AuthService } from './auth.service';
import { AngularFirestore } from '@angular/fire/compat/firestore';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { AngularFirestoreMock } from '../../testing/mock_angularFirestore';
import { AngularFireAuthMock } from '../../testing/mock_angularFireAuth';

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

  beforeEach(() => {
    TestBed.configureTestingModule(
      {
        providers: [
          {provide: AngularFirestore, useValue: AngularFirestoreMock},
          {provide: AngularFireAuth, useVallue: AngularFireAuthMock} // 存在拼写错误:useVallue → useValue
        ]

      });
    service = TestBed.inject(AuthService);
  });

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

已实现的有效模拟

AngularFirestoreMock

export const AngularFirestoreMock = {
  set: () => {}
};

AuthServiceMock

export const AuthServiceMock = jasmine.createSpy('userData')
  .and.returnValue(Promise.resolve({
    uid: 'fakeuser',
    email: 'test@test.com',
    emailVerified: true
  }));

需要模拟的AngularFireAuth方法及返回值

  • authState.subscribe():返回Observable<User | null>(注意不是Promise)
  • createUserWithEmailAndPassword:Promise
  • sendEmailVerification:Promise
  • signOut:Promise
  • signInWithEmailAndPassword:Promise
  • sendPasswordResetEmail:Promise
  • currentUser:在compat版本中是**Promise<User | null>**类型的属性

正确的AngularFireAuthMock实现

import { of } from 'rxjs';
import { UserCredential } from '@angular/fire/auth';

// 模拟用户对象
const mockUser = {
  uid: 'fakeuser',
  email: 'test@test.com',
  emailVerified: true,
  sendEmailVerification: () => Promise.resolve()
};

// 模拟UserCredential
const mockUserCredential: Partial<UserCredential> = {
  user: mockUser,
  credential: null
};

export const AngularFireAuthMock = jasmine.createSpyObj('AngularFireAuth', [
  'createUserWithEmailAndPassword',
  'signOut',
  'signInWithEmailAndPassword',
  'sendPasswordResetEmail'
], {
  // 属性模拟
  authState: of(mockUser), // authState是Observable,用of包装模拟值
  currentUser: Promise.resolve(mockUser)
});

// 给每个方法设置返回值
AngularFireAuthMock.createUserWithEmailAndPassword.and.returnValue(Promise.resolve(mockUserCredential as UserCredential));
AngularFireAuthMock.signOut.and.returnValue(Promise.resolve());
AngularFireAuthMock.signInWithEmailAndPassword.and.returnValue(Promise.resolve(mockUserCredential as UserCredential));
AngularFireAuthMock.sendPasswordResetEmail.and.returnValue(Promise.resolve());

关键修正点

  • 拼写错误修复:测试代码里的useVallue改为useValue,这是导致注入失败的直接原因之一。
  • authState类型修正:authState是Observable而非Promise,要用rxjs的of创建模拟流。
  • 方法拼写修正:把错误的signout改为正确的signOut。
  • 返回值匹配类型:确保每个方法的返回值和AngularFireAuth的实际类型一致,比如sendEmailVerification返回空Promise,而非带错误码的对象。
  • currentUser模拟:compat版本中currentUser是Promise类型的属性,直接返回Promise.resolve(mockUser)即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 14:56:07