不推荐直接修改实例原型链来 mock 深度嵌套调用;应使用分层 mock、工厂函数或依赖注入等方式安全拦截调用路径,避免污染原型、破坏类型和逻辑。

直接修改实例的原型链来 mock 深度嵌套调用,不是推荐做法。Object.getPrototypeOf 本身是只读访问器,不能用于“设置”行为;真正起作用的是 Object.setPrototypeOf 或构造时控制原型,配合 jest.mock / spyOn 等测试工具才能安全、可维护地拦截链式调用。
明确目标:不是改原型,而是拦截调用路径
深度链式调用(如 user.org.department.manager.name)本质是一连串属性访问和方法执行。单元测试中要 mock 的不是“原型对象”,而是中间任意一环的返回值或行为。强行用 Object.setPrototypeOf 替换实例原型容易引发:
- 污染真实原型链,影响其他测试用例
- 绕过类定义逻辑(如 getter/setter、constructor 行为)
- 对 TypeScript 类型不友好,丢失类型推导
- 无法处理动态计算属性或私有字段
推荐方案:分层 mock + 工厂函数构造测试数据
针对嵌套实例,用 plain object 或轻量 mock 对象替代真实类实例,更简单可靠:
- 用
jest.mock模拟整个模块,导出可控的嵌套结构 - 用工厂函数(如
createMockUser())生成带默认嵌套结构的普通对象 - 对关键方法使用
jest.fn(),例如:const mockManager = { name: 'Alice', getId: jest.fn().mockReturnValue(101) }; - 让
department.manager直接返回该 mock,无需继承或原型操作
极少数需干预原型时:用 Object.setPrototypeOf + restore 清理
仅当被测代码**强依赖 instanceof 或原型上特定方法**(如自定义 toString),且无法重构时,才临时替换原型:
- 保存原始原型:
const originalProto = Object.getPrototypeOf(instance); - 创建新 mock 原型并设置:
Object.setPrototypeOf(instance, mockProto); - 在
afterEach中恢复:Object.setPrototypeOf(instance, originalProto); - 避免对全局类(如 Date、Array)或 shared 实例做此操作
更健壮的替代思路:依赖注入 + 接口抽象
从根本上解耦嵌套依赖:
- 将
user.org.department.manager这类长路径封装成服务方法(如UserContext.getManagerName()) - 在测试中注入 mock 服务,而非 mock 原始实例
- 用 TypeScript interface 定义契约,测试只关心输入输出,不关心实现层级
- 这样既提升可测性,也增强代码可维护性


















