
测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载导读Sandbox沙箱是 Sinon 中管理测试替身fake、spy、stub、mock生命周期的核心机制它消除了逐个追踪、逐个清理每个 fake 的负担。本文以 docs/concepts/sandboxes/api/_index.md 为主线系统讲解默认沙箱的使用方式、14 个核心方法与 2 个属性的完整语义并结合 src/sinon/sandbox.js 与 src/sinon/create-sandbox.js 的源码实现深入剖析其创建—收集—恢复的底层原理。读完本文你将掌握如何用sinon对象本身完成测试替身的统一管理与清理也会知道何时应该创建自定义沙箱。默认沙箱Default sandbox从sinon5.0.0开始sinon对象本身就是一个默认沙箱。这意味着在绝大多数测试场景中你无需手动创建沙箱实例直接通过sinon.spy()、sinon.stub()、sinon.mock()等全局 API 创建的每一个测试替身都会被默认沙箱自动记录在册测试结束时只需调用一次sinon.restore()就能把所有替身一次性还原。源码层面src/sinon/sandbox.js 中Sandbox构造函数会维护一个内部collection数组所有通过沙箱方法创建的 fake、spy、stub、mock 以及 clock 都会被addToCollection()推入该数组而restore()会对collection逆序逐个调用其restore方法见下文restore 的逆序恢复原理。在 docs/tests/docs/sandboxes/api/_index.test.js 中有对应的验证用例import t from tap; import sinon from sinon; t.test(default sandbox can stub and restore properties, (t) { const myObject { hello: world }; // Stub the property sinon.stub(myObject, hello).value(Sinon); // Verify the stub works t.equal(myObject.hello, Sinon, property should be stubbed to Sinon); // Restore sinon.restore(); // Verify restoration t.equal(myObject.hello, world, property should be restored to world); t.end(); });运行上述测试可以看到sinon.stub()替换了属性值而一次sinon.restore()即完整恢复了原始值。除非你的测试环境有非常高级的特殊需求否则默认沙箱就是官方推荐的用法。方法Methods默认沙箱拥有与自定义沙箱完全一致的方法集合。下面逐一说明每个方法的语义与源码实现要点。sandbox.createStubInstance()详细用法见 sandbox.createStubInstance。该方法与工具函数sinon.createStubInstance完全等价传入一个构造函数返回该构造函数对应实例的替身实例上所有自有方法都会被自动 stub。在 src/sinon/sandbox.js 中sandbox.createStubInstance会先调用sinonCreateStubInstance生成替身再通过collectOwnMethods收集替身实例上的所有自有方法逐个加入collection确保这些方法也能被沙箱统一恢复。sandbox.mock()详细用法见 sandbox.mock。与全局sinon.mock完全等价用于创建 mock 并对方法设置预期expectation。源码src/sinon/sandbox.js中mock 创建后同样被addToCollection(m)收录因此sandbox.verify()和sandbox.restore()会自动覆盖到它。sandbox.replace()详细用法见 sandbox.replace。sandbox.replace(object, property, replacement);将object上的property替换为replacement并返回replacement本身。replacement可以是任意值包括 fakes、spies 和 stubs 的实例。需要注意的边界行为重复替换会抛异常verifyNotReplaced()src/sinon/sandbox.js会检查fakeRestorers中是否已存在针对同一objectproperty的恢复器若已存在则抛出TypeError(Attempted to replace ... which is already replaced)。只支持普通属性throwOnAccessors()src/sinon/sandbox.js会在描述符存在get/set时抛出错误提示改用replaceGetter/replaceSetter。类型必须一致verifySameType()src/sinon/sandbox.js要求replacement与原始值的typeof相同否则抛出TypeError。不存在的属性会报错checkForValidArguments()src/sinon/sandbox.js会提示Perhaps you meant sandbox.define()?。恢复机制上每次replace都会通过getFakeRestorer()生成一个恢复函数并推入fakeRestorers数组恢复时若属性是自有属性则用Object.defineProperty还原描述符否则直接delete。sandbox.replaceGetter()与sandbox.replaceSetter()详细用法见 sandbox.replaceGetter 与 sandbox.replaceSetter。分别用于替换属性的 getter 与 settersandbox.replaceGetter(object, property, replacement); sandbox.replaceSetter(object, property, replacement);replacement必须是一个函数可以是fake、spy或stub实例。源码src/sinon/sandbox.js中的约束包括属性必须存在不存在抛出TypeErrorreplacement必须为函数否则抛TypeError(Expected replacement argument to be a function)原属性必须真的是 getter/setter否则抛Error(object.propertyis not a getter/setter)描述符必须可配置configurable为false时抛TypeError同样禁止重复替换。实现上通过Object.defineProperty重写get/set同时保留原enumerable设置并登记恢复器供restore()使用。sandbox.reset()重置沙箱内所有替身的行为 历史记录。源码src/sinon/sandbox.js通过applyOnEach(collection, reset)与applyOnEach(collection, resetHistory)依次调用applyOnEach会过滤出拥有对应方法的 fake 再逐个调用。sandbox.resetBehavior()仅重置所有替身的行为即returns、throws等通过.returns()配置的默认行为不清空调用历史。实现见 src/sinon/sandbox.js。sandbox.resetHistory()仅清空所有替身的调用历史callCount、args、calledWith等记录不触碰行为配置。注意其实现src/sinon/sandbox.js对每个 fake 优先调用resetHistory若不存在则回退到reset。sandbox.restore()详细用法见 sandbox.restore。恢复沙箱内所有通过它创建的 fakes、spies、stubs 及替换过的属性。调用时不接受任何参数若误传参数会抛出Error(sandbox.restore() does not take any parameters. Perhaps you meant stub.restore())src/sinon/sandbox.js。逆序恢复原理源码先对fakeRestorersreplace/replaceGetter/replaceSetter/define产生的恢复器做reverse后依次执行并清空再对collection做reverse后逐个调用restore最后将collection置空。逆序LIFO恢复保证了后创建、后替换的替身先被还原避免依赖关系错乱。sandbox.spy()、sandbox.stub()、sandbox.fake()sandbox.spy()与sinon.spy等价创建 spy 并登记到沙箱sandbox.stub()与sinon.stub等价创建 stub 并登记到沙箱sandbox.fake()与sinon.fake等价创建 fake 并登记到沙箱。三者源码实现src/sinon/sandbox.js都通过withContext传入一个沙箱专属的sandboxContext{ callId: 0 }用于在并行测试之间隔离callId追踪避免并发执行时调用 ID 串扰。此外spy/stub都会通过extend继承sinonSpy/sinonStub上的静态工具方法。sandbox.useFakeTimers()详细用法见 sandbox.useFakeTimers。启用 fake timers 并挂载为sandbox.clock同时将 clock 加入collectionsrc/sinon/sandbox.js。这样sinon.restore()或sandbox.restore()会一并恢复真实的计时器。sandbox.verify()详细用法见 sandbox.verify。对沙箱内所有 mock 执行预期校验src/sinon/sandbox.js不满足预期时抛出异常。sandbox.verifyAndRestore()先执行verify()再无条件执行restore()若verify()抛出了异常则保存异常、完成恢复后重新抛出src/sinon/sandbox.js。这个设计保证即使断言失败测试环境也一定被清理干净。属性Propertiessandbox.assert详细用法见 sandbox.assert。通过sinonAssert.createAssertObject(assertOptions)创建与沙箱绑定的断言对象src/sinon/sandbox.js。assertOptions可在createSandbox配置中传入用于定制断言行为参见 src/sinon/assert.js。测试中可直接使用sandbox.assert.calledWith(spy, ...)等形式对替身做断言。sandbox.leakThreshold详细用法见 sandbox.leakThreshold。获取/设置内存泄漏检测警告的阈值默认值为10000见 src/sinon/sandbox.js 的DEFAULT_LEAK_THRESHOLD。当addToCollection使collection长度超过该阈值时沙箱会打印警告仅警告一次提示你确保每个测试后都调用了restore()将该属性调大可关闭告警src/sinon/sandbox.js。自定义沙箱sinon.createSandbox()当默认沙箱不够用时例如多个测试并行且需要彼此隔离、或需要注入替身到全局对象、或需要默认开启 fake timers可以通过sinon.createSandbox创建独立的沙箱。基础用法见 docs/tests/docs/sandboxes/_index-2.test.jsimport tap from tap; import * as sinon from sinon; tap.test(sandbox - using a custom sandbox, (t) { const sandbox sinon.createSandbox(); const myObject { hello: world }; // using the stub method on the sandbox sandbox.stub(myObject, hello).value(Banana); t.equal(myObject.hello, Banana, property stubbed to Banana); sandbox.restore(); t.equal(myObject.hello, world, property restored to world); t.end(); });createSandbox的配置项从 src/sinon/create-sandbox.js 的SandboxConfig类型定义可以看出sinon.createSandbox(config)支持以下配置配置项类型说明propertiesstring[]要在沙箱上暴露的 API 属性列表例如[spy, fake, restore]injectIntoobject将沙箱属性注入到的目标对象外观模式sinon-test等集成工具使用useFakeTimersboolean \| object是否默认启用 fake timers传对象时作为计时器配置传入useFakeTimersassertOptionsobject断言对象配置见 src/sinon/assert.js源码执行流程src/sinon/create-sandbox.js无配置时直接返回new Sandbox()有配置时先按useFakeTimers是否设置来预配置沙箱prepareSandboxFromConfig初始化injectedKeys与injectInto调用sandbox.inject({})生成暴露对象若指定了properties则遍历列表把对应方法暴露到injectInto或压入sandbox.args否则默认暴露sandbox本身。inject的实现见 src/sinon/sandbox.js它会向目标对象注入spy、stub、mock、createStubInstance、fake、define、replace、replaceSetter、replaceGetter、match等成员并在启用了 fake timers 时注入clock。使用自定义沙箱的场景建议多个测试文件/用例需要独立隔离的替身集合互不干扰需要把spy、stub等方法注入全局对象以兼容旧的测试写法需要沙箱默认开启 fake timers避免每个用例重复调用useFakeTimers()需要独立的断言配置assertOptions。除此之外官方文档的建议是尽量只使用默认沙箱。相关阅读Sandboxes 概念总览沙箱设计的背景与两种使用方式对比创建沙箱指南更详细的自定义沙箱创建流程Fakes 概念、Spies 概念、Stubs 概念、Mocks 概念沙箱管理的各类替身对象Fake timers 概念useFakeTimers的行为细节测试用例目录 docs/tests/docs/sandboxes/沙箱各 API 的完整 tap 测试示例赞分享测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载相关推荐OpenRouter 音频内容块转换实现解析effect/ai-openrouter 的 input_audio 支持OpenRouter 音频内容块转换实现解析effect/ai openrouter 的 input_audio 支持 本篇围绕 effect/ai op测试开发工具AssetRipper 新手教程3 步完成首次 Unity 资源提取与逆向分析AssetRipper 新手教程3 步完成首次 Unity 资源提取与逆向分析 从 Unity 游戏里提取纹理、音频、网格和脚本不用再手动翻文件结构。Ass开发工具逆向工程游戏开发Sinon 沙箱中的 sandbox.spy与默认沙箱协同的测试间谍实战指南Sinon 沙箱中的 sandbox.spy与默认沙箱协同的测试间谍实战指南 导读 在 Sinon 中 sandbox.spy 是沙箱Sandbox体系测试开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考