使用Jest模拟Express控制器导入的ES模块失败求助
解决Jest模拟Express控制器中ESM模块失效的问题
问题原因
Jest处理ES模块时,模块导入是静态的。如果在mock设置完成前就导入了依赖目标模块的代码(比如你的Express服务器或控制器),原始模块会被提前加载,导致mock规则无法生效。你当前的测试直接使用了提前导入的server,但server依赖的控制器已经加载了未被mock的module_to_mock.js。
解决方案
核心是先设置mock规则,再动态导入依赖该mock的模块,同时修正mock的导出格式以匹配ESM的默认导出规范。
修改后的测试代码
// message_controller.test.js // 1. 先配置mock,注意返回格式要匹配ESM默认导出结构 jest.unstable_mockModule('./module_to_mock.js', () => ({ default: jest.fn().mockReturnValue(true) })); test('Mock successfully', async () => { // 2. 在测试内部动态导入server和被mock的模块 const { default: server } = await import('./server.js'); // 替换为你的实际server文件路径 const { default: moduleToMock } = await import('./module_to_mock.js'); const messageToSend = 'hello'; const response = await server.post('/message').send({ message: messageToSend }); expect(response.body.message).toEqual(`Mock works: ${messageToSend}`); // 可选:验证mock函数确实被调用过 expect(moduleToMock).toHaveBeenCalled(); });
关键注意事项
- 禁止在测试文件顶部静态导入
server或控制器,必须在jest.unstable_mockModule之后用await import()动态导入,确保mock规则在模块加载前生效。 jest.unstable_mockModule的回调函数必须返回包含default字段的对象,对应原模块的默认导出,这是ESM模块的导出要求。- 如果你的
server文件在启动时就加载了控制器,动态导入server会确保控制器在mock设置完成后才被加载,从而应用mock规则。
内容的提问来源于stack exchange,提问作者Yılmaz Kasap
相关产品推荐
相关产品推荐

