js部分mock核心是精准替换需控制的函数,保持其余真实逻辑;推荐用jest.mock()配合requireactual实现安全覆盖,或spyon动态替换已加载模块方法,proxy适用于无框架场景。

在 JS 模块化开发中,有选择地 Mock 部分函数(即 Partial Mock),核心是“只替换需要控制的行为,其余保持真实逻辑”,避免全量 mock 导致测试失真或维护成本上升。关键不在于“能不能 mock”,而在于“怎么让 mock 精准生效且不破坏模块原有结构”。
用 jest.mock() + requireActual 实现安全的部分覆盖
这是 Jest 用户最推荐的方式,适用于 ESM 或 CommonJS 模块,前提是被测模块通过 具名导出(如 export { fnA, fnB })提供函数。
- 必须在
import语句之前调用jest.mock(),否则 mock 不会拦截模块加载过程 - 用
jest.requireActual('./module')获取原始模块对象,再手动覆盖指定方法 - 未被覆盖的导出项(如其他函数、常量、工具对象)仍走真实逻辑
示例:
jest.mock('./api', () => {
const actual = jest.requireActual('./api');
return {
...actual, // 保留全部原始导出
fetchUser: jest.fn().mockResolvedValue({ id: 1, name: 'Mocked' }),
};
});
<p>// 后续 import './api' 就会拿到这个混合对象
import { fetchUser, fetchPost } from './api';
// fetchUser 是 mock,fetchPost 仍是真实函数</p>用 spyOn 替换已加载模块中的方法
适合在测试内部动态控制,尤其当模块已被导入、且导出的是可变对象(非冻结)时。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 先
require(不是import)目标模块,获取其导出对象引用 - 用
jest.spyOn(module, 'methodName').mockImplementation(...)替换单个方法 - 需配合
afterEach(() => jest.restoreAllMocks())防止测试间污染
注意:该方式对 default 导出或箭头函数直接赋值的模块无效,仅适用于导出对象属性形式(module.exports = { fn: () => {} })。
用 Proxy 创建运行时包装器(无框架场景)
当不使用 Jest 或需轻量级、运行时控制时,可用 Proxy 手动拦截特定属性访问。
- 对原始模块对象创建代理,
get拦截器判断属性名决定返回 mock 还是原值 - 完全绕过模块系统限制,不依赖任何测试框架
- 适合调试、本地开发 mock,或集成到非 Jest 测试环境(如 Vitest 自定义 mock)
示例:
const realLogger = require('./logger');
const mockLogger = new Proxy(realLogger, {
get(target, prop) {
if (prop === 'error') {
return (...args) => console.log('[MOCKED] ERROR:', ...args);
}
return target[prop];
}
});
// 使用 mockLogger 代替 realLogger 即可
避开常见陷阱
部分 mock 容易失败,往往不是写法错,而是机制没对齐:
-
不要在
it内部调用jest.mock()—— 它只在模块初始化阶段生效 -
避免硬编码调用内部函数:如果模块 A 内部直接调用了同模块的函数 B,而不是通过导出对象访问(如
exports.B),那 mockB就不会影响 A 的行为 -
ESM 默认导出要小心:用
import * as mod from比import mod from更容易成功spyOn -
检查对象是否被冻结:
Object.isFrozen(module)为true时,直接赋值module.fn = mock会静默失败










