单元测试中修改原型应严格限于测试作用域内并立即还原,优先采用局部对象模拟或 reflect.setprototypeof 动态切换,避免污染全局原型;冻结关键原型可提升测试健壮性。

在单元测试中修改原型不是为了“生产可用”,而是为了隔离、模拟或验证行为。关键不在于“能不能改”,而在于“改得可控、可恢复、不影响其他测试”。直接污染全局原型(比如 Array.prototype.push)会引发跨测试污染,必须避免。
只在测试作用域内临时修改
把原型修改限制在单个 describe 或 it 块内,并在结束后立即还原:
- 用
beforeEach保存原始方法:const originalToString = String.prototype.toString; - 在测试中覆盖:
String.prototype.toString = jest.fn(() => 'mocked'); - 用
afterEach恢复:String.prototype.toString = originalToString; - 注意:若测试运行在严格模式下,且目标原型已被
Object.freeze(),赋值会直接抛错——此时应跳过该测试或换用代理方案
优先用 Object.assign 或 Object.defineProperty 模拟
比起直接改原生原型,更推荐对测试对象本身做“局部原型替换”:
- 创建干净的测试对象:
const testObj = Object.assign(Object.create(YourPrototype), { value: 42 }); - 用
Object.defineProperty控制特定属性行为,例如让testObj.toString返回固定值,而不碰String.prototype - 这样所有修改都局限在该对象实例,完全不干扰全局环境
用 Reflect.setPrototypeOf 配合可恢复的原型对象
当确实需要动态切换实例的原型链(如测试继承委托逻辑),用 Reflect.setPrototypeOf 更规范,但必须配合清理:
- 先保存原原型:
const oldProto = Object.getPrototypeOf(instance); - 设置新原型:
Reflect.setPrototypeOf(instance, mockProto); - 断言完成后还原:
Reflect.setPrototypeOf(instance, oldProto); - 注意:如果
instance已被Object.freeze(),这一步会失败,需提前检查或跳过
冻结关键原型作为测试前提
在测试套件启动时(如 setupFilesAfterEnv),主动冻结常用原生原型,把“意外修改”变成“立刻报错”:
Object.freeze(String.prototype);Object.freeze(Array.prototype);Object.freeze(Object.prototype);- 这样任何试图在测试中篡改它们的操作都会立即失败,反而提升了测试的健壮性和可调试性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











