javascript mock 构造函数和 class 的核心是接管 new 调用,通过替换构造函数、模块级 mock 或 proxy 拦截实现可控模拟实例;需注意原型链、私有成员、es 模块限制及测试后清理。

JavaScript 中 Mock 构造函数和 class,核心是拦截实例化行为、替换原型链或控制 new 调用的返回值,让测试时能返回可控的模拟对象(而非真实实例)。关键不在于“删掉类”,而在于“接管 new”。
直接替换构造函数(最常用)
适用于简单场景,比如只想让 new ApiClient() 返回一个带预设方法的对象:
- 保存原始构造函数(便于恢复)
- 用
jest.fn()或自定义函数覆盖类名引用 - 在 mock 函数中返回你想要的模拟实例(可含 stub 方法、spy 属性等)
示例:
const OriginalClient = ApiClient;ApiClient = jest.fn().mockImplementation(() => ({
fetchData: jest.fn().mockResolvedValue({ ok: true }),
baseUrl: 'https://mock.api'
}));
// 测试后可还原:ApiClient = OriginalClient;
Mock 类的静态方法或构造行为(需 Jest 27+)
当类本身有静态工厂方法(如 ApiClient.create())或你想控制 new 的逻辑时:
- 用
jest.mock('./ApiClient')自动 mock 整个模块 - 再通过
__mocks__/ApiClient.js提供定制实现,包括重写constructor和静态方法 - 或使用
jest.requireActual()保留部分真实逻辑,只替换构造逻辑
注意:直接 mock 类名变量(如 class ApiClient{} 后再赋值)在 ES 模块中可能受限,推荐用模块级 mock。
用 Proxy 拦截 new 调用(高级控制)
若需细粒度控制每次 new 的行为(例如不同参数返回不同 mock 实例),可用 Proxy 包装构造函数:
- 创建代理构造函数,
constructtrap 中判断参数并返回对应 mock 对象 - 保持原构造函数的
prototype,确保 instanceof 仍有效(可选) - 适合集成测试或需要动态响应的 mock 场景
示例片段:
const RealApiClient = ApiClient;ApiClient = new Proxy(RealApiClient, {
construct(target, args) {
if (args[0] === 'test') {
return { id: 'mock-1', getData: () => 'stubbed' };
}
return new target(...args); // fallback
}
});
避免常见陷阱
Mock class 容易踩坑,尤其涉及继承或 this 绑定时:
- 不要只 mock 实例方法而忽略原型链——mock 后的实例可能仍从原 prototype 查找方法
- 若类有私有字段(#field)或私有方法,普通 mock 无法访问,需用实际实例 +
jest.spyOn替换特定方法 - ES 模块下,直接赋值
class X {}后再改X = ...会报错(const 不可重赋),应优先 mock 模块导出 - 测试结束后记得
jest.restoreAllMocks()或手动清理,防止 mock 泄漏影响其他测试
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











