如何使用Jasmine或ng-mocks模拟Firebase的onAuthStateChanged方法
解决方案
要模拟直接导入的@angular/fire/auth中的函数,核心是将导入方式改为模块对象导入,这样Jasmine就能通过spyOn拦截函数调用。以下是具体实现步骤:
1. 修改原服务的导入与调用方式
将单独导入的函数改为从模块对象中引用,这样后续才能被 spy 拦截:
// 原导入方式 // import { Auth, getAuth, onAuthStateChanged, User } from '@angular/fire/auth'; // 修改为模块对象导入 import * as angularFireAuth from '@angular/fire/auth'; // 服务内的代码调整为: const app = initializeApp(environment.firebase); this.auth = angularFireAuth.getAuth(app); this.db = getDatabase(); // 使用模块对象调用 onAuthStateChanged angularFireAuth.onAuthStateChanged(this.auth, (user) => { // ... 原有逻辑 });
2. 在测试文件中模拟onAuthStateChanged
在测试用例中,通过spyOn模拟模块对象上的onAuthStateChanged方法,根据不同场景传入模拟用户或null:
import { TestBed } from '@angular/core/testing'; import { YourAuthService } from './your-auth.service'; import * as angularFireAuth from '@angular/fire/auth'; describe('YourAuthService', () => { let service: YourAuthService; beforeEach(() => { TestBed.configureTestingModule({ // 无需额外注入,因为我们直接模拟模块函数 }); service = TestBed.inject(YourAuthService); }); it('应处理已登录状态', () => { // 创建模拟用户实例 const mockUser: angularFireAuth.User = { uid: 'test-user-id', email: 'test@example.com', // 按需添加其他必要属性 } as angularFireAuth.User; // 模拟 onAuthStateChanged:调用回调时传入模拟用户 spyOn(angularFireAuth, 'onAuthStateChanged').and.callFake((auth, callback) => { callback(mockUser); // 返回空的 unsubscribe 函数,避免报错 return () => {}; }); // 初始化服务(触发 onAuthStateChanged 调用) service = TestBed.inject(YourAuthService); // 断言已登录状态下的逻辑是否执行正确 // 例如:expect(service.currentUser).toEqual(mockUser); }); it('应处理未登录状态', () => { // 模拟 onAuthStateChanged:调用回调时传入 null spyOn(angularFireAuth, 'onAuthStateChanged').and.callFake((auth, callback) => { callback(null); return () => {}; }); service = TestBed.inject(YourAuthService); // 断言未登录状态下的逻辑是否执行正确 // 例如:expect(service.currentUser).toBeNull(); }); });
关键说明
- 改用模块对象导入是核心:单独导入的函数是直接引用,Jasmine 无法拦截;而模块对象的属性可以被
spyOn劫持。 callFake用于自定义函数的执行逻辑,这里直接调用传入的回调函数,模拟 auth 状态变化的触发。- 务必返回一个空的
Unsubscribe函数,避免因返回值不符合类型定义导致的测试报错。
内容的提问来源于stack exchange,提问作者lukasniessen
相关产品推荐
相关产品推荐

