Angular单元测试中使用firestore.Timestamp.now()的问题
1. 这是预期行为吗?
是的,这完全是预期行为。Firebase SDK的设计逻辑要求必须先调用initializeApp完成核心初始化,之后各个服务(比如Firestore)的命名空间和相关API才会被挂载到firebase/app导出的对象上。angularfire2作为Firebase的Angular封装库,完全依赖底层Firebase SDK的初始化流程,所以只有在TestBed中初始化AngularFireModule后,firestore.Timestamp这类API才能正常访问,否则就会出现undefined的报错。
2. 是否无法在Firebase Angular项目之外创建firestore Timestamp数据类型?
不是的,你完全可以在非Angular项目中使用Firestore Timestamp,但前提是要正确初始化Firebase核心SDK。比如在纯JavaScript/TypeScript项目中,只要完成以下步骤:
- 导入
firebase/app和firebase/firestore - 调用
firebase.initializeApp()(哪怕用一个测试用的空配置对象,不需要真实的Firebase项目信息)
之后就能正常使用firestore.Timestamp.now()这类方法了。本质上不是依赖Angular框架,而是依赖Firebase核心SDK的初始化流程。
3. 未执行initializeApp时为何firestore会是undefined?
这是Firebase SDK模块化加载和初始化机制导致的。当你只导入import { firestore } from 'firebase/app'时,这个firestore只是一个预留的命名空间占位符,只有当你调用initializeApp后,Firebase才会加载并注册Firestore服务,把对应的API(包括Timestamp)挂载到这个命名空间下。这种设计是为了确保所有服务都在完成配置初始化后才可用,避免出现未配置就调用API的错误场景。
单元测试小建议
在你的单元测试中,不需要连接真实的Firebase项目,只需要在TestBed中初始化AngularFireModule时传入一个测试用的配置即可,比如:
AngularFireModule.initializeApp({ apiKey: 'test-key', authDomain: 'test-domain', projectId: 'test-project' })
这样既满足了Firebase初始化的要求,又不会影响单元测试的独立性和速度。另外,如果你不想依赖真实的Firebase SDK初始化,也可以手动Mock一个Timestamp类来替代,比如:
class MockTimestamp { static now() { return { toDate: () => new Date() }; } }
在测试中用这个Mock类替代真实的firestore.Timestamp即可。
内容的提问来源于stack exchange,提问作者DauleDK

