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

如何用Jest模拟类?测试指定代码时遇问题需解决

问题描述

我想了解如何通过模拟对象来测试以下代码,已尝试遵循Jest官方文档但仍无法成功。

源代码(somefile.ts)

export const myPublish = async (event: any, context: any): Promise<any> => {
  const myExportHelper = await ExportHelper.getInstance({
    ...commonProps,
  });

  // just some other stuff
  // just some other stuff

  await myExportHelper.transfer(arg1, arg2);
};

export class ExportHelper {
  constructor(
    private readonly bucket: string,
    private readonly read: AWS.S3,
    private readonly write: AWS.S3
  ) {}

  static async getInstance(props: {
    param1: string;
  }) {
    ...
    ...

    return new ExportHelper(arg1, arg2, arg3);
  };

  async transfer(param1, param2) {
    ...
    ...
    console.log('bla bla bla');
  }
}

当前测试代码(testfile.test.ts)

import { myPublish, ExportHelper } from '../somefile';

beforeEach(() => {
});

afterEach(() => {
    jest.clearAllMocks();
    jest.resetAllMocks();
});

describe('myTest', () => {
    it('should run successfully', async () => {
        // Arrange
        const eventMock = {
            Records: [
                {
                    ...
                }
            ]
        }

        jest.mock('../somefile');
        const mockActualExportHelper = jest.requireActual('../somefile').ExportHelper;
        
        const mockGetInstanceImpl = () => {};

        // 此处报错:无法读取undefined的instances属性
        const mockExportHelper = mockActualExportHelper.mock.instances[0]; 
        mockExportHelper.getInstance.mockImplementation(mockGetInstanceImpl);
        mockExportHelper.transfer.mockImplementation(mockGetInstanceImpl);

        // Act
        await myPublish(eventMock, jasmine.any({}));

        // Assert
        expect(ExportHelper.getInstance).toBeCalled();
        expect(ExportHelper.transfer).toBeCalled(); // 同时不确定此断言是否有效
        
    });
});
解决方案

你的测试代码存在几个核心问题,以下是修正方案和问题说明:

问题点梳理

  1. jest.mock放置位置错误:jest.mock必须放在文件顶部(import语句之后),Jest需要在模块加载阶段就完成mock替换,放在测试用例内部会导致mock不生效。
  2. 混淆真实类与mock类:你通过jest.requireActual获取了真实的ExportHelper类,它没有Jest mock专属的mock属性,因此会触发“无法读取undefined的instances属性”的错误。
  3. 断言对象错误:transfer是实例方法,不是静态方法,直接断言ExportHelper.transfer被调用完全无效,应该断言mock实例的transfer方法。

修正后的测试代码(简洁版)

import { myPublish, ExportHelper } from '../somefile';

// 提前mock模块,确保加载时替换原始类
jest.mock('../somefile');

describe('myTest', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it('should run successfully', async () => {
    // Arrange
    const eventMock = { Records: [{}] };
    // 创建mock实例,包含mock的transfer方法
    const mockHelperInstance = { transfer: jest.fn() };
    // 让静态方法getInstance返回mock实例
    (ExportHelper.getInstance as jest.Mock).mockResolvedValue(mockHelperInstance);

    // Act
    await myPublish(eventMock, {});

    // Assert
    expect(ExportHelper.getInstance).toHaveBeenCalled();
    expect(mockHelperInstance.transfer).toHaveBeenCalled();
    // 如果需要验证参数,可改成:
    // expect(mockHelperInstance.transfer).toHaveBeenCalledWith(期待的参数1, 期待的参数2);
  });
});

关键说明

  • 静态方法mock:ExportHelper.getInstance是静态方法,需要通过类型断言as jest.Mock将其转换为Jest mock函数,才能设置返回值。
  • 实例方法断言:必须对getInstance返回的mock实例的transfer方法做断言,而非直接断言类的静态方法。
  • mock时机:jest.mock必须放在测试代码之前,确保模块加载时就完成替换,否则原始类会被正常加载,mock失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:30:36