测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载Sinon 的sandbox.replace()用于在测试中临时替换对象上的任意属性方法、字符串、数值乃至 fake/spy/stub并将原始值登记在沙箱的还原队列中随sandbox.restore()一并自动恢复。它省去了手动保存与还原原值的样板代码是隔离被测对象依赖、注入测试替身的核心手段。读完本文你将掌握replace()的参数规则、同类型校验、异常边界、访问器属性的替代方案replaceGetter/replaceSetter及其底层还原机制。方法签名与基本语义sandbox.replace是沙箱 API 中的一个方法官方文档定义如下sandbox.replace(object, property, replacement);其语义为将object上的property属性替换为replacement参数并返回replacement。它属于 沙箱 API 方法列表 中的一员从sinon5.0.0起sinon根对象本身就是一个默认沙箱因此可以直接调用sinon.replace(...)无需手动创建沙箱。替换过程并非简单的属性赋值——沙箱会在背后记录一个还原器restorer当调用sandbox.restore()时会把属性还原为替换前的值从而保证测试之间互不污染。在 src/sinon/sandbox.js 中可以找到该方法的真实实现其执行流程包含四道校验见下文异常与边界一节随后通过push(fakeRestorers, getFakeRestorer(object, property))登记还原器再执行object[property] replacement完成替换。返回值返回 replacement 本身replace()会返回传入的replacement参数便于链式使用或立即持有引用。这一点在 test/src/sandbox-test.js 中有对应测试将replacement传入后断言返回值actual与replacement严格相等。一个实用的写法是让替换函数直接作为返回值被捕获const sandbox sinon.createSandbox(); const object { method() { return original; } }; const fakeMethod sandbox.replace(object, method, sinon.fake.returns(mocked)); fakeMethod(); // mocked object.method(); // mockedreplacement 可以是任意值这是replace()与replaceGetter/replaceSetter的一个关键差异replacement可以是任何类型的值不限于函数。官方文档明确说明它可以包含fakes、spies和stubs。具体来说函数替换函数最常见的场景例如用 stub 替换被测模块依赖的方法字符串/数值等原始值替换同类型值如替换配置对象的字段fake/spy/stub 替换方法替换后该属性立即拥有 Sinon 的断言与行为能力。test/src/sandbox-test.js 中的测试证明了非函数属性字符串同样可以被替换并在restore()后还原。同类型校验不允许跨类型替换虽然replacement可以是任意值但原属性与替换值必须是同一 JavaScript 类型。源码中的verifySameType校验src/sinon/sandbox.js会对比typeof original与typeof replacementif (originalType ! replacementType) { throw new TypeError(Cannot replace ${originalType} with ${replacementType}); }对应测试位于 test/src/sandbox-test.js用函数替换字符串属性 → 抛出Cannot replace string with function用字符串替换函数属性 → 抛出Cannot replace function with string。这一设计避免了替换后调用方行为不可预期的隐性故障例如把方法误替换成字符串导致运行期TypeError: not a function。异常与边界情况官方文档明确指出Attempting to replace an already replaced value causes an exception.尝试替换一个已被替换的值会抛出异常。结合源码replace()在赋值前会依次执行四道校验校验步骤触发条件异常信息源码位置checkForValidArguments属性不存在无属性描述符Cannot replace non-existent property X. Perhaps you meant sandbox.define()?src/sinon/sandbox.jscheckForValidArgumentsreplacement为undefinedExpected replacement argument to be defined同上verifyNotReplaced该属性已被同一沙箱替换过Attempted to replace X which is already replacedsrc/sinon/sandbox.jsthrowOnAccessors属性是 getterUse sandbox.replaceGetter for replacing getterssrc/sinon/sandbox.jsthrowOnAccessors属性是 setterUse sandbox.replaceSetter for replacing setters同上verifySameType原值与替换值类型不一致Cannot replace X with Ysrc/sinon/sandbox.js几个值得注意的细节重复替换限制无论是函数还是字符串同一对象同一属性在同一沙箱内只能替换一次第二次调用会抛TypeError。测试见 test/src/sandbox-test.js。非可写属性的陷阱如果属性由Object.defineProperty定义为writable: false但仍 configurablereplace()通过赋值方式写入时会抛原生错误Cannot assign to read only property ...且属性保持不变相关测试见 test/src/sandbox-test.js。访问器属性请使用 replaceGetter / replaceSetter官方文档强调replace()只作用于非访问器non-accessor属性。对于 getter/setter应当改用sandbox.replaceGetter(object, property, replacement)替换 getterreplacement必须是函数sandbox.replaceSetter(object, property, replacement)替换 setterreplacement必须是函数。若对访问器属性调用replace()会直接抛出Error而非TypeError提示改用对应方法见 test/src/sandbox-test.js。这两个方法同样支持替换继承来的访问器并在restore()后还原测试见 test/src/sandbox-test.js。如果你的确需要用赋值方式替换访问器属性例如对象同时定义了 getter 与 setter、且底层状态由外部变量承载replace()还有一个非文档化的变体sandbox.replace.usingAccessor(object, property, replacement)它跳过访问器检测、直接走赋值路径测试示例见 test/src/sandbox-test.js。日常测试优先使用replaceGetter/replaceSetter即可。与 restore() 的生命周期管理自动还原replace()的最大价值在于与sandbox.restore()配合实现自动清理。还原流程在 src/sinon/sandbox.js 中实现restore()会逆序执行fakeRestorers数组中的还原器再逆序对collection中的 fake 逐个调用restore。每个还原器由getFakeRestorer生成src/sinon/sandbox.js其还原策略是描述符敏感的属性原本是对象自有属性记录替换前的完整属性描述符还原时通过Object.defineProperty恢复——包括enumerable、writable等属性特征而不仅仅是值属性是继承自原型链的替换会在对象上创建自有属性shadowing还原时执行delete object[property]移除该自有属性使原型上的原值重新可见。test/src/sandbox-test.js 对这两种还原路径分别做了验证还原后自有属性恢复原描述符如enumerable: false保持原样继承属性则被取消遮蔽、恢复读取原型值。看一个官方文档测试中的完整生命周期示例来自 docs/tests/docs/sandboxes/api/restore.test.jsconst obj { one: 1, two: 2, three: 3 }; sinon.replace(obj, one, apple); sinon.replace(obj, two, banana); sinon.replace(obj, three, cherry); // obj 现在为 { one: apple, two: banana, three: cherry } sinon.restore(); // obj 恢复为 { one: 1, two: 2, three: 3 }与 sandbox.define() 的区别替换 vs 定义replace()要求属性必须已经存在否则抛出Cannot replace non-existent property ... Perhaps you meant sandbox.define()?。这个错误信息同时指向了沙箱的另一方法sandbox.define(object, property, value)实现见 src/sinon/sandbox.jsreplace替换已存在的属性要求同类型define在对象上新增一个原本不存在或来自原型但非自有的属性同样会被沙箱登记并在restore()时删除且不要求类型一致。两条路径的错误信息互为提示define对已存在属性也会提示Perhaps you meant sandbox.replace()?测试见 test/src/sandbox-test.js。选择原则很简单属性原本就有就用replace原本没有就用define。完整实战示例以下示例改编自官方文档测试 docs/tests/docs/sandboxes/api/replace.test.js演示了默认沙箱下的最小用法import * as sinon from sinon; // sinon 根对象即默认沙箱 const myObject { myMethod: function () { return apple pie; }, }; sinon.replace(myObject, myMethod, function () { return strawberry; }); const result myObject.myMethod(); // result strawberry方法已被替换 sinon.restore(); // myObject.myMethod 恢复为返回 apple pie 的原函数结合 stub 的行为能力做依赖替换const sandbox sinon.createSandbox({ useFakeTimers: true }); const service { fetchData: () Promise.resolve(real data) }; // 用 stub 替换方法并预置返回值 const stub sandbox.replace( service, fetchData, sandbox.stub().resolves(mocked data), ); await service.fetchData(); // mocked data stub.calledOnce; // true sandbox.restore(); // 同时清理 stub 与替换常见注意事项小结replace()每次调用前都会校验未被替换过同一属性的重复替换会抛异常需要先restore()或使用不同沙箱替换值必须与原始属性同类型否则抛TypeError访问器属性getter/setter请改用replaceGetter/replaceSetterrestore()是描述符敏感的自有属性按原描述符还原继承属性通过删除自有遮蔽属性还原若目标属性尚未定义应使用sandbox.define()而不是replace()默认沙箱sinon根对象已具备全部沙箱 API除非需要独立配置如单独的useFakeTimers、injectInto等否则无需手动createSandbox。赞分享测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载相关推荐Sinon Sandbox 的 replaceSetter精确替换对象 Setter 的完整指南Sinon Sandbox 的 replaceSetter精确替换对象 Setter 的完整指南 导读 sandbox.replaceSetter objec测试开发工具CVAT 半自动与自动标注Serverless AI 工具安装与部署指南CVAT 半自动与自动标注Serverless AI 工具安装与部署指南 导读 本文面向希望在自托管 CVATComputer Vision Annota测试开发工具HivisionIDPhotosAI 证件照生成器CPU 30 秒出成品照HivisionIDPhotosAI 证件照生成器CPU 30 秒出成品照 入职前 1 小时发现交上去的蓝底证件照不合规格打印店又已打烊。Hivisio测试开发工具上一篇UpscalerJS 开源项目入门指南下一篇Sveltia CMS移动端体验响应式设计如何完美适配不同设备创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考