单元测试验证浅拷贝有效性,关键在于断言函数执行后原始对象所有层级值是否完全不变;应保存原始快照、调用函数、用深比较(如toequal或isequal)验证全路径一致性,而非仅检查顶层引用是否不同。

在单元测试中验证浅拷贝是否有效,关键不是“检查拷贝动作本身”,而是**断言函数执行后原始数据是否保持不变**。因为浅拷贝只隔离第一层,真正风险来自函数内部对嵌套引用的修改——这正是测试要捕获的漏洞。
明确测试目标:只关心“副作用”是否发生
不要测 Object.assign({}, obj) 是否返回了新对象,而要测:函数调用后,原始对象所有层级的值(尤其嵌套属性)是否与调用前完全一致。
- ✅ 正确思路:保存原始快照 → 调用被测函数 → 深比较原始对象和当前状态
- ❌ 错误思路:只比对顶层引用是否不同(这只能证明做了拷贝,不能证明没污染)
推荐断言方式:用深比较库验证全路径不变
浅拷贝无法阻止深层修改,所以测试必须穿透到最内层。直接用 JSON.stringify() 不可靠(会丢 Date、undefined 等),建议用成熟断言工具:
- Jest:用
expect(original).toEqual(expected)—— 它默认做深度相等判断,且能清晰报错定位哪一层变了 - 或手动深比较:用
lodash.isEqual(original, originalAfterCall) - 简单场景可序列化时:用
JSON.stringify(original) === JSON.stringify(originalAfterCall)(仅限纯数据对象)
写测试时的关键操作步骤
以一个典型易出错函数为例:
假设函数updateUserProfile(user) 内部做了浅拷贝但错误地修改了 user.address.city
- 准备原始对象:
const original = { id: 1, name: '张三', address: { city: '北京' } }; - 保存快照:
const snapshot = JSON.parse(JSON.stringify(original));(或用structuredClone) - 调用函数:
updateUserProfile(original); - 断言:
expect(original).toEqual(snapshot);—— 若失败,说明函数意外改了原始数据
避免测试盲区的两个细节
有些修改不会触发常规深比较报错,需额外关注:
-
数组 length 或稀疏索引:如
arr.push(x)改了 length,isEqual能捕获;但arr[99] = 'x'可能被忽略,建议配合Object.keys(arr)检查 -
特殊类型值变化:Date 对象修改
.setFullYear()后仍是同一实例,toEqual会认为相等(因比的是对象引用)。此时应显式检查original.date.getTime() === snapshot.date.getTime()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











