如何在Jest中Mock通过import导入的CommonJS模块
问题
我用Jest测试一个通过import导入CommonJS格式外部库(ganblib.js)的类时,Mock操作未生效,但把被测试类里的import换成require就能正常Mock。相关代码如下:
待Mock的外部库(ganblib.js)
module.exports = class GanbLib { constructor({clientID, clientSecret, nonceCallbacks}) { // 业务代码 } async refreshTokens(refreshToken, tryCounter = 0) { // 业务代码 } }
被测试类
import express from 'express' import GanbLib from './ganblib.js' const controller = express.Router() controller.post('/api/endpoint', async (req, res) => { const clientOptions = { clientID: 'client_id', clientSecret: 'secrete_id', nonceCallbacks: [()=>{}, ()=>{}], } const ganbLib = new GanbLib(clientOptions) ganbLib .refreshTokens('refresh_token') .then((result) => { // 业务处理代码 }) })
测试类
import request from 'supertest' describe('POST /api/endpoint', () => { const endpoint = '/api/endpoint' test('refresh token', async () => { const mockRefreshTokens = jest.fn().mockResolvedValue({ access_token: 'token', refresh_token: null, }) jest.mock('./ganblib.js', () => { return jest.fn().mockImplementation(() => { return { refreshTokens: mockRefreshTokens } }) }) await request(app).post(endpoint).expect(200) }) })
已配置.babelrc处理ES模块:
{ "env": { "test": { "presets": [ [ "@babel/preset-env", { "targets": { "node": "current" } } ] ] } } }
需求:如何用import而非require实现正常Mock?
解决方案
问题核心是ES模块的静态导入机制——import会在代码执行前被解析,而原测试中jest.mock写在测试函数内部,此时被测试类已完成真实GanbLib的导入,Mock无法覆盖。按以下步骤修改即可:
1. 将jest.mock移到测试文件顶部,优先于所有import
Jest会自动提升jest.mock调用到模块最顶部执行,确保被测试类导入GanbLib前,Mock已生效。
2. 可选:动态导入被测试模块
若测试环境对ES模块处理有延迟,可在测试用例内部动态导入Express应用/路由,保证Mock完全生效后再加载业务代码。
修改后的测试类示例
// 先定义Mock函数并执行jest.mock,确保优先处理 const mockRefreshTokens = jest.fn().mockResolvedValue({ access_token: 'token', refresh_token: null, }) jest.mock('./ganblib.js', () => { return jest.fn().mockImplementation(() => { return { refreshTokens: mockRefreshTokens } }) }) // 再导入依赖和被测试模块 import request from 'supertest' import app from './your-app-entry.js' // 替换为你的Express应用导出文件路径 describe('POST /api/endpoint', () => { const endpoint = '/api/endpoint' test('refresh token', async () => { // 重置Mock调用记录,避免用例间干扰 mockRefreshTokens.mockClear() await request(app).post(endpoint).expect(200) // 验证Mock函数被正确调用 expect(mockRefreshTokens).toHaveBeenCalledWith('refresh_token') }) })
额外说明
- 即使你把
jest.mock写在import之后,Jest也会自动提升它的执行顺序,但显式放在顶部更易维护。 - 若动态导入更稳妥,可将
import app改为测试用例内的const { default: app } = await import('./your-app-entry.js'),进一步确保Mock加载时机正确。
内容的提问来源于stack exchange,提问作者Yuto Ueki
相关产品推荐
相关产品推荐

