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

将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();
  });
});

关键细节解释

  1. jest.mock的位置:必须放在模块最顶部,Jest会自动把这个调用提升到所有import之前,确保AngularFirestore类被正确mock。
  2. 类型定义:用jest.Mocked<T>可以给mock对象添加完整的类型提示,就像Jasmine的SpyObj<T>一样,解决你“想要给mock添加类型”的需求。
  3. 实例化mock类:因为AngularFirestore是一个类,我们需要创建它的mock实例,而不是直接操作类本身——这和Jasmine中createSpyObj创建实例spy的逻辑是对应的。
  4. 链式mock:先创建collection的mock,再让firestore的collection方法返回它,和你之前Jasmine的firestoreSpy.collection.and.returnValue(firestoreCollectionSpy)逻辑一致。

这样调整后,你就能正确模拟AngularFirestore及其collection方法,不会再出现collection属性undefined的错误了。

内容的提问来源于stack exchange,提问作者Robert Field

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 19:52:45