不推荐用 getprototypeof mock 嵌套类行为,应优先采用依赖注入+构造器参数解耦、jest.mock/vi.mock 模拟构造函数,必要时才谨慎使用 object.setprototypeof 临时干预并严格还原。

直接用 getPrototypeOf mock 嵌套类行为并不推荐——它不是为测试 mock 设计的工具,强行使用反而增加复杂度、降低可维护性。真正高效的方式是结合构造函数原型链控制 + 依赖注入 + 有针对性的 spy/stub,而不是操作原型链本身。
避免直接操作 getPrototypeOf
Object.getPrototypeOf() 仅用于读取对象的原型,不能安全地“替换”或“劫持”嵌套类的实例行为。试图通过修改原型链来 mock 深层依赖(比如 A → B → C 中的 C),会导致:
- 测试副作用污染其他用例(原型是共享的)
- 难以还原原始行为,易引发泄漏
- TypeScript 类型推导失效,IDE 提示不准
- 与现代测试框架(如 Jest/Vitest)的 mock 机制不兼容
用依赖注入 + 构造器参数解耦嵌套关系
把嵌套类作为参数传入,而非在内部 new 出来。这样测试时可直接传入 stub 实例:
// 被测类class ServiceA {<br> constructor(private serviceB: ServiceB) {}<br> doWork() {<br> return this.serviceB.doSomething();<br> }<br>}
// 测试中
const mockB = { doSomething: vi.fn().mockReturnValue('ok') };<br>const sut = new ServiceA(mockB);<br>sut.doWork();<br>expect(mockB.doSomething).toHaveBeenCalled();
对无法修改的第三方嵌套类,用 jest.mock 或 vi.mock 模拟构造函数
当必须 mock new SomeNestedClass()(比如第三方 SDK 内部创建了深层实例),应 mock 其构造函数,而非操作原型:
- Jest:
jest.mock('./SomeNestedClass', () => { return class SomeNestedClass { ... } }) - Vitest:
vi.mock('./SomeNestedClass', async (importOriginal) => { const mod = await importOriginal(); return { ...mod, default: class Mocked { ... } }; }) - 确保 mock 类返回可控的子实例(例如让它的方法返回预设值或 spy)
必要时用 Object.setPrototypeOf 临时干预(仅限极少数边界场景)
如果确实要临时替换某个实例的原型(例如绕过 final 类限制),可用 Object.setPrototypeOf,但必须:
- 在测试前保存原始原型:
const originalProto = Object.getPrototypeOf(instance) - 仅在
beforeEach中替换,afterEach中严格还原 - 只用于不可控的遗留代码,新代码禁止此模式
不复杂但容易忽略:mock 的目标永远是“行为”,不是“原型结构”。聚焦接口契约,比折腾原型链更稳定、更可读、更易协作。











