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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:44:54