如何使用Jest测试JavaScript函数是否存在副作用
Jest 通用无副作用检测测试实现
核心检测逻辑完全通用,不绑定特定函数或特定类型入参,核心思路很简单:调用函数前留存所有入参的深拷贝快照,函数执行完成后,逐一比对实际传入的参数和原始快照是否完全一致,不一致就说明函数修改了入参、存在副作用。
完整的测试文件代码如下:
import myFunction from "./myFunction.js"; /** * 通用无副作用校验工具 * @param {Function} fn 待测函数 * @param {...any} args 传入待测函数的任意数量、任意类型参数 * @returns 待测函数的返回值 */ function assertNoSideEffects(fn, ...args) { // 对所有入参做深拷贝,留存原始状态快照 const originalSnapshots = args.map(arg => structuredClone(arg)); // 正常执行待测函数 const result = fn(...args); // 逐个校验入参:执行后状态必须和原始快照完全一致 args.forEach((actualArg, idx) => { expect(actualArg).toEqual(originalSnapshots[idx]); }); return result; } test("that there are no side-effects", () => { // 自定义你的测试入参即可 const myArray = [1, 2, { test: "嵌套值" }, 4]; // 传入待测函数和对应入参,自动完成副作用校验 assertNoSideEffects(myFunction, myArray); });
方案说明
- 适配所有场景:不管待测函数接收多少个参数,参数是数组、嵌套对象、Map/Set/Date等特殊类型,还是基础类型值,只要按顺序把参数传给
assertNoSideEffects即可,不需要为每个用例单独写比对逻辑 - 深拷贝实现采用原生
structuredClone,Node 17+、所有现代测试环境默认支持,比JSON.parse(JSON.stringify())支持的数据类型更全;如果你的环境版本过低,可以替换为lodash的_.cloneDeep,比对逻辑不需要任何修改 - 校验逻辑和函数返回值完全解耦:不管待测函数有没有返回值、返回什么内容,都不会干扰入参是否被篡改的检测结果
- 不影响Jest其他能力:如果需要用
jest.spyOn模拟函数内部依赖、做返回值断言等,都可以正常写,和普通测试用例写法没有区别
内容的提问来源于stack exchange,提问作者Rolazar
相关产品推荐
相关产品推荐

