如何用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(); // 同时不确定此断言是否有效 }); });
解决方案
你的测试代码存在几个核心问题,以下是修正方案和问题说明:
问题点梳理
jest.mock放置位置错误:jest.mock必须放在文件顶部(import语句之后),Jest需要在模块加载阶段就完成mock替换,放在测试用例内部会导致mock不生效。- 混淆真实类与mock类:你通过
jest.requireActual获取了真实的ExportHelper类,它没有Jest mock专属的mock属性,因此会触发“无法读取undefined的instances属性”的错误。 - 断言对象错误:
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
相关产品推荐
相关产品推荐

