将Jasmine SpyObj模拟转为Jest模拟:Angular测试迁移问题
解决AngularFirestore Jest模拟中collection属性undefined的问题
我明白你在从Jasmine迁移到Jest时遇到的这个困扰了——Jest的模拟逻辑和Jasmine的createSpyObj确实有些不一样,咱们一步步来修复这个问题。
问题根源
你遇到的TypeError: Cannot read property 'mockImplementation' of undefined,主要是两个原因:
jest.mock()是被**提升(hoisted)**到模块顶部执行的,你把它放在beforeEach里会导致模拟没有正确生效,firestoreMock.collection自然就找不到对应的mock属性。- 直接用
mocked(AngularFirestore, true)模拟的是类本身,而不是类的实例,所以实例方法collection并没有被正确mock。
正确的模拟方式
下面是对应你Jasmine代码的Jest实现,同时保留类型提示:
import { mocked } from 'ts-jest/utils'; import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore'; import { of } from 'rxjs'; import { TestBed } from '@angular/core/testing'; // 把jest.mock放在模块顶部,确保它被正确提升 jest.mock('@angular/fire/firestore'); // 定义类型,让我们的mock有完整的类型提示 type MockedAngularFirestore = jest.Mocked<AngularFirestore>; type MockedAngularFirestoreCollection = jest.Mocked<AngularFirestoreCollection<any>>; describe('Jest Tests', () => { let firestoreMock: MockedAngularFirestore; let firestoreCollectionMock: MockedAngularFirestoreCollection; beforeEach(() => { // 创建collection的mock实例 firestoreCollectionMock = { snapshotChanges: jest.fn().mockReturnValue(of()) } as MockedAngularFirestoreCollection; // 获取AngularFirestore的mock类,然后创建实例 const MockAngularFirestore = mocked(AngularFirestore); firestoreMock = new MockAngularFirestore() as MockedAngularFirestore; // 让collection方法返回我们的mock collection firestoreMock.collection.mockReturnValue(firestoreCollectionMock); // 如果是在Angular测试中,别忘了把mock注入TestBed TestBed.configureTestingModule({ providers: [ { provide: AngularFirestore, useValue: firestoreMock } ] }); }); it('My Test', () => { // 这里可以根据需要覆盖snapshotChanges的返回值 firestoreCollectionMock.snapshotChanges.mockReturnValue(of([/* 你的测试数据 */])); // 执行你的测试逻辑... // 验证方法调用(可选) expect(firestoreMock.collection).toHaveBeenCalled(); expect(firestoreCollectionMock.snapshotChanges).toHaveBeenCalled(); }); });
关键细节解释
jest.mock的位置:必须放在模块最顶部,Jest会自动把这个调用提升到所有import之前,确保AngularFirestore类被正确mock。- 类型定义:用
jest.Mocked<T>可以给mock对象添加完整的类型提示,就像Jasmine的SpyObj<T>一样,解决你“想要给mock添加类型”的需求。 - 实例化mock类:因为AngularFirestore是一个类,我们需要创建它的mock实例,而不是直接操作类本身——这和Jasmine中
createSpyObj创建实例spy的逻辑是对应的。 - 链式mock:先创建collection的mock,再让firestore的collection方法返回它,和你之前Jasmine的
firestoreSpy.collection.and.returnValue(firestoreCollectionSpy)逻辑一致。
这样调整后,你就能正确模拟AngularFirestore及其collection方法,不会再出现collection属性undefined的错误了。
内容的提问来源于stack exchange,提问作者Robert Field
相关产品推荐
相关产品推荐

