测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载本文围绕 Sinon 沙箱SandboxAPI 中的sandbox.stub()方法展开讲解它与全局sinon.stub()完全一致的行为语义、在沙箱内的自动收集与恢复机制以及最常被问到的非函数属性non-function propertystubbing实战用法。读完本文你将掌握如何在测试中通过sandbox.stub(obj, prop).value(newVal)临时替换对象的普通数据属性字符串、数字、对象等并在测试结束时通过一次restore()自动还原现场彻底告别手动清理。sandbox.stub()是什么根据 docs/concepts/sandboxes/api/stub.md 的官方定义sandbox.stub()与sinon.stub的用法完全一致。这意味着你可以在沙箱上使用sinon.stub的全部能力包括包装已有函数sandbox.stub(obj, method)替换对象方法且不会调用原始函数预编程行为通过.returns()、.throws()、.callsFake()、.resolves()、.rejects()、.yields()等方法定义返回值、抛错、回调等行为按调用次数差异化响应通过.onCall(n)让 stub 在连续调用时表现不同stub 非函数属性通过.value(newVal)直接替换对象的普通数据属性。两者唯一的差异在于生命周期管理由沙箱创建的 stub 会被自动登记进沙箱的收集列表调用sandbox.restore()时一次性还原而全局sinon.stub()创建的 stub 需要手动调用stub.restore()或依赖默认沙箱的sinon.restore()。默认沙箱sinon 对象本身就是沙箱从sinon5.0.0起sinon对象本身就是一个沙箱即默认沙箱它拥有与沙箱 API 完全相同的全部方法与属性见 docs/concepts/sandboxes/index.md 与 sandbox API 索引。因此最推荐、最简洁的用法是直接调用sinon.stub()与sinon.restore()无需显式创建沙箱。这一设计在 src/sinon/create-sandbox.js 的注释中有明确印证As of Sinon 5 the sinon instance itself is a Sandbox, so you hardly ever need to create additional instances for the sake of testing自定义沙箱当需要隔离的配置如独立的 assert 选项、useFakeTimers、或injectInto注入目标时可以通过sinon.createSandbox(config)创建独立沙箱。createSandbox支持的关键配置项定义于 src/sinon/create-sandbox.jsproperties要暴露在沙箱上的 API 属性名列表例如[spy, fake, restore]injectInto将沙箱方法注入到指定对象中主要用于集成场景如 sinon-testuseFakeTimers是否默认启用假定时器传对象时可携带定时器配置assertOptions断言选项。Stubbing 非函数属性.value(newVal)沙箱 stub 的核心扩展场景是替换非函数属性。普通stub(obj, prop)只能替换函数类型的属性而数据属性字符串、数字、布尔值、对象等需要通过.value()来定义新值。完整可运行示例以下示例直接取自仓库文档测试 docs/tests/docs/sandboxes/api/stub.test.js展示了stub 非函数属性 → 验证 → 沙箱恢复 → 验证还原的完整闭环import t from tap; import sinon from sinon; t.test(sandbox.stub can stub non-function properties, (t) { const sandbox sinon.createSandbox(); const myObject { hello: world }; // Stub the property sandbox.stub(myObject, hello).value(Sinon); // Verify the stub works t.equal(myObject.hello, Sinon, property should be stubbed to Sinon); // Restore via sandbox sandbox.restore(); // Verify restoration t.equal(myObject.hello, world, property should be restored to world); t.end(); });执行流程拆解sandbox.stub(myObject, hello)在沙箱中登记 stub 并替换该属性.value(Sinon)将属性值临时定义为Sinonstub.value 文档 中定义该方法为为 stub 定义一个新值断言确认myObject.hello Sinonsandbox.restore()一次性还原沙箱内所有 stub断言确认属性恢复为原始值world。使用默认沙箱的等价写法如果不显式创建沙箱直接使用默认沙箱即可效果完全一致见 docs/tests/docs/sandboxes/_index-1.test.jsimport tap from tap; import * as sinon from sinon; const myObject { hello: world }; // 使用默认沙箱的 stub 方法 sinon.stub(myObject, hello).value(Sinon); tap.equal(myObject.hello, Sinon, property stubbed to Sinon); sinon.restore(); tap.equal(myObject.hello, world, property restored to world);局部恢复调用stub.restore()除了通过沙箱整体恢复也可以只恢复单个 stub。.value()会返回 stub 本身因此可以保留引用并单独调用其restore()方法参见 docs/tests/docs/stubs/api/value-2.test.jsconst stub sinon.stub(myObj, example).value(newValue); tap.equal(myObj.example, newValue, property has new value); stub.restore(); tap.equal(myObj.example, oldValue, property restored to old value);注意sandbox.restore()与stub.restore()是有区别的——前者不带参数、一次性还原沙箱内全部 fake后者只还原当前 stub。若误给sandbox.restore()传参源码 src/sinon/sandbox.js 会抛出sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()的明确提示。源码视角沙箱 stub 的底层机制sandbox.stub的实现在 src/sinon/sandbox.js 中sandbox.stub的实现核心如下sandbox.stub function () { // 将沙箱上下文作为首参传入用于并行测试间隔离 callId const args arrayProto.concat( [sandboxContext], arrayProto.slice(arguments), ); const createdStub sinonStub.withContext.apply(sinonStub, args); const result commonPostInitSetup(arguments, createdStub, true, /* ... */); addReturnedMethodsToCollection(result); return result; };关键点通过sinonStub.withContext传入sandboxContext该上下文对象{ callId: 0 }见 src/sinon/sandbox.js用于隔离并行测试之间的调用 ID 计数commonPostInitSetup会把创建的 stub 加入沙箱收集列表addToCollectionaddReturnedMethodsToCollection还会把 stub 行为链返回的对象中自有方法一并收集确保.onCall()产生的派生 stub 也能被统一还原。非函数属性 stubbing 的底层判定sinon.stub的入口实现在 src/sinon/stub.js 的stubImpl中stub.withContext(context, object, property)最终都会落到它src/sinon/stub.js。当目标属性不是函数时stub 不会去包装执行逻辑而是直接返回一个可供.value()赋值的 stub 对象return isStubbingNonFuncProperty ? s : wrapMethod(object, property, s);此外stubImpl会对不存在的属性抛出明确错误Cannot stub non-existent property ...并对不可配置non-configurable或不可写non-writable的属性描述符进行校验src/sinon/stub.js提醒你检查属性描述符配置。恢复机制的实现sandbox.restore()的实现src/sinon/sandbox.js会按逆序遍历收集列表并逐个调用restore()从而保证依赖顺序正确还原reverse(collection); applyOnEach(collection, restore); collection [];同时沙箱还提供了细粒度的重置能力全部作用于收集列表中的所有 fakesrc/sinon/sandbox.jssandbox.reset()重置行为与历史sandbox.resetBehavior()仅重置行为sandbox.resetHistory()仅清空调用历史sandbox.verify()校验所有 mock 期望sandbox.verifyAndRestore()先verify()再restore()若校验失败则抛出异常src/sinon/sandbox.js。泄漏防护沙箱内置了泄漏阈值保护默认DEFAULT_LEAK_THRESHOLD 10000见 src/sinon/sandbox.js 与 src/sinon/sandbox.js当收集的 fake 数量超过阈值且未恢复时会打印警告提醒你在每个测试后restore。你可以通过修改沙箱的leakThreshold属性来调整或关闭该警告详见 leak-threshold 文档。何时使用sandbox.stub()结合 stubs 概念文档 的指引在以下场景优先使用 stub并通过沙箱管理生命周期控制方法行为以驱动特定代码路径例如让方法抛出错误以测试错误处理逻辑如stub.throws(new Error(I lost my pie :())阻止副作用方法被真实调用例如替换fs.readFile以返回测试所需的假数据如sinon.stub(fs, readFile).callsFake(() Promise.resolve(Apple pie))替换非函数数据属性这是sandbox.stub().value()的专属能力适合临时改写配置项、常量或状态字段按调用次数差异化响应行为定义方法如.returns()、.throws()多次调用会相互覆盖此时用.onCall(n)指定每次调用的行为on-call 文档。需要留意的是Sinon 官方对新建代码推荐优先使用 fakes如sinon.fake.returns()、sinon.fake.throws()因其行为更简单、不可变且同样支持 spy API但 stub 在onCall()差异化行为与属性 stubbing等高级场景中仍然不可或缺——这正是sandbox.stub().value()的价值所在。小结sandbox.stub()与sinon.stub()行为完全一致但多了一层沙箱托管所有由沙箱创建的 stub 会被自动收集sandbox.restore()一次性完成还原。对于非函数属性通过.value(newVal)可以轻松实现临时替换并借助沙箱或单个 stub 的restore()确保测试结束后原始值无损还原。无论是默认沙箱sinon.stub()还是sinon.createSandbox()自定义沙箱这一模式都能让测试 teardown 变得更简洁、更不易出错。赞分享测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载相关推荐Sinon sandbox.replace() 完全指南安全替换对象属性并自动还原Sinon sandbox.replace 完全指南安全替换对象属性并自动还原 Sinon 的 sandbox.replace 用于在测试中临时替换对象上的任测试开发工具Sinon spy.restore 完全指南将 Spy 与 Stub 恢复为原始方法Sinon spy.restore 完全指南将 Spy 与 Stub 恢复为原始方法 导读 spy.restore 是 Sinon 测试框架中用于清理现场测试开发工具Sinon stub.set 完全指南替换与模拟 JavaScript 对象属性 SetterSinon stub.set 完全指南替换与模拟 JavaScript 对象属性 Setter stub.set setterFn 是 Sinon 测试桩S测试开发工具上一篇BilibiliDown轻松搞定B站视频下载打造个人专属离线资源库下一篇如何彻底移除 ralph-claude-code从零残留到干净系统的完整操作创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
客户管理系统落地实践:桌面端CRM设计、自动化与数据安全 做了这么多年的客户管理系统落地,我一直觉得CRM这个品类被不少团队走偏了:不是功能堆得越多越好,而是真正贴合一线人员的工作习惯和信息流转方式才能用起来。DeskcommCRM是我前几年主导设计并落地的一套桌面端客户关系管理系统,英… · 2026/9/25 11:38:49
命令注入漏洞原理、绕过手法与多层防御实战指南 1. 命令注入到底是什么:从一次代码审计说起1.1 一次真实的代码审计现场有次我给一个内部系统做代码审计,看的是一个导出报表的后端接口。功能很简单:用户填一个设备IP,系统后台ping这个IP,然后把连通结果写进日志文件。… · 2026/9/25 11:38:31
基于springboot的民宿预定信息管理系统 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片!
技术栈
后端框架:Spring Boot 2.x,提供快速开发、自动配置和嵌入式Tomcat支持。数据库:MySQL 8.0,用于存储民宿、用户、… · 2026/9/25 12:20:13
通用 CRUD 接口设计:用 TaoToken 统一 Key 打通 params 校验与数据库模型 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 12:19:48
西湖大学Code World Model解读:用Coding Agent做世界模型大脑的工程化落地 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 12:19:42
Atlas 300V 24G部署YOLO实战:从模型转换到性能调优的完整指南 最近后台和社群里问得最多的两个问题,一个是“atlas 300V 24G 这张卡到底是不是运算加速卡”,另一个是“atlas 上能不能部署 YOLO”。我本来以为问的人多是刚入行的朋友,后来发现不少工作三五年的老手也在问,说明这个组合确实有门… · 2026/9/25 12:19:36
本地视频素材库自动化整理:yt-dlp+ffmpeg+Whisper实践 这次我们来看一个非常具体的折腾场景:想把油管上散落的 Artcore 风格音乐视频整理成规整的本地素材库,应该怎么用现成工具链一次性跑通。Artcore 本身不是一个开源项目名,而是电子音乐社区里视觉和听觉绑定很紧密的一类风格标签:节… · 2026/9/25 12:19:36
影视NLP实战:美剧台词情感分析模型构建 我无法根据您提供的输入内容生成符合要求的博文。原因如下:项目标题"The.Walking.Dead行尸走肉"是一部广为人知的美国电视剧(《行尸走肉》),属于影视文化领域;但项目正文为空,关键词为空… · 2026/9/25 12:19:30
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37