Sinon 中 stub.callsArgWith 深度解析:按参数索引触发回调并传入指定实参
测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载Sinon 的stub.callsArgWith(index, ...args)是 stub 行为配置家族中最常用的成员之一它让 stub 在被调用时把调用实参列表中位于index位置的参数当作回调函数立即执行并把预先声明的参数原样传入该回调。本文以 stub.callsArgWith 官方文档 为核心结合 Sinon 源码与测试用例讲解其用法、错误处理、底层实现原理以及与callsArg系列其他方法的选型关系帮助你写出可复现、可维护的基于回调的测试桩。功能概述与典型应用场景stub.callsArgWith(index)的行为是当 stub 被调用时将其第index个实参当作回调函数进行调用并将callsArgWith声明时传入的后续参数...args作为该回调的实参。它最常见的应用场景是模拟 Node.js 风格的 error-first 回调接口例如// 被测代码调用 API并在回调中处理结果 function loadUser(api, id, callback) { api.getUser(id, callback); }在测试中我们并不想真正发起网络请求而是希望api.getUser被调用时立即以固定参数回调从而驱动被测逻辑继续执行const sinon require(sinon); const api { getUser: sinon.stub() }; api.getUser.callsArgWith(1, null, { id: 1, name: Alice }); // 第 1 个参数是回调 loadUser(api, 42, (err, user) { console.log(user.name); // Alice });这样一来测试不需要等待真实异步 I/O回调同步执行、结果确定非常适合单元测试中验证回调驱动的代码路径。方法签名与参数说明stub.callsArgWith(index, ...args)参数类型说明indexnumber回调在 stub 调用实参列表中的位置从 0 开始计数...args任意调用回调时传入的实参列表原样透传给回调两个关键约定index必须是一个数字。若省略或传入非数字如{}会立即抛出TypeError详见下文“错误处理”。...args可以省略。此时回调会被调用但不传入任何实参相当于callback()这一点与 stub.callsArg 的行为一致——区别只在于callsArg不接收、也不传递任何参数给回调。方法链式返回 stub 本身因此可以继续级联其他行为配置如.onCall(...)、.returns(...)等。基本用法示例以下示例取自文档配套测试 docs/tests/docs/stubs/api/calls-arg-with.test.jsconst sinon require(sinon); // 第 0 个参数是回调回调被调用时传入三个水果名 const stub sinon.stub().callsArgWith(0, apple, banana, cherry); const callback sinon.fake(); stub(callback); callback.calledOnce; // true callback.calledWith(apple, banana, cherry); // true对应的核心源码测试位于 test/src/stub-test.js覆盖了更多细节// 回调位于非 0 索引位置 const stub createStub().callsArgWith(1, object); const callback createStub(); stub(1, callback); assert(callback.calledWith(object)); // 不传任何回调实参 const stub2 createStub().callsArgWith(1); stub2(1, callback); assert(callback.calledWith()); // 传多个实参 const stub3 createStub().callsArgWith(1, object, array); stub3(1, callback); assert(callback.calledWith(object, array));从上面可以看出回调参数的位置与回调实参的数量彼此独立index只负责“从哪里取回调”...args只负责“回调收到什么”。错误处理文档明确说明当指定索引位置的参数不可用或不是函数时会抛出Error。结合源码callsArgWith涉及两类共三种错误1. 配置期错误index不是数字在调用stub.callsArgWith()声明行为时就会立即校验。源码位于 src/sinon/default-behaviors.jscallsArgWith: function callsArgWith(fake, index) { if (typeof index ! number) { throw new TypeError(argument index is not number); } fake.callArgAt index; fake.callbackArguments slice(arguments, 2); fake.callbackContext undefined; fake.callArgProp undefined; fake.callbackAsync false; fake.callsThrough false; },测试验证test/src/stub-test.jsstub.callsArgWith(); // TypeError stub.callsArgWith({}); // TypeError2. 调用期错误实参数量不足stub 被调用时如果实参总数小于等于index即取不到第index个参数会抛出TypeError。该校验由 src/sinon/behavior.js 中的ensureArgs完成function ensureArgs(name, behavior, args) { const property name.replace(/sArg/, ArgAt); // callsArg callArgAt const index behavior[property]; if (index args.length) { throw new TypeError( ${name} failed: ${index 1} arguments required but only ${args.length} present, ); } }3. 调用期错误该位置参数不是函数即使实参数量足够若第index个实参不是函数也会抛出TypeError。错误消息格式为argument at index ${index} is not a function: ${func}src/sinon/behavior.js。文档配套测试给出了直接证据docs/tests/docs/stubs/api/calls-arg-with.test.jsconst stub sinon.stub().callsArgWith(0, apple, banana, cherry); // 实参是 undefined不是函数 → 抛错 t.throws( () stub(undefined), /argument at index 0 is not a function/, throws when argument is not a function );底层实现原理调用链剖析callsArgWith的完整调用链分为“配置”与“调用”两个阶段。配置阶段写入 stub 行为当执行stub.callsArgWith(1, a, b)时src/sinon/behavior.js 中的createBehavior会将callsArgWith注册到 stub 的默认行为对象上并写入以下内部状态src/sinon/default-behaviors.jscallArgAt index记录回调在实参列表中的位置callbackArguments [...args]记录要透传给回调的实参slice(arguments, 2)截取除fake与index之外的所有参数callbackContext undefined回调的this指向callsArgWith不指定上下文相关能力由callsArgOnWith提供callbackAsync false同步调用异步版本见下文callsThrough false覆盖此前可能设置的callThrough行为。调用阶段提取并执行回调stub 被调用时src/sinon/behavior.js 的invoke会最先执行callCallback其位置刻意放在所有其他行为之前function callCallback(behavior, args) { if (typeof behavior.callArgAt number) { ensureArgs(callsArg, behavior, args); // 1. 校验实参数量 const func getCallback(behavior, args); // 2. 按索引取出回调 if (typeof func ! function) { // 3. 校验是函数 throw new TypeError(getCallbackError(behavior, func, args)); } if (behavior.callbackAsync) { nextTick(function () { func.apply(behavior.callbackContext, behavior.callbackArguments); }); } else { return func.apply(behavior.callbackContext, behavior.callbackArguments); } } return undefined; }其中getCallbacksrc/sinon/behavior.js在callArgAt 0时直接返回args[callArgAt]即按索引精确取参——这正是callsArg/callsArgWith家族与yields家族自动寻找“最左/最右回调”的本质区别。返回值语义invoke中callCallback的返回值会被保留并在没有其他行为如returns、throws抢占时作为 stub 的返回值返回src/sinon/behavior.js。因此stub.callsArgWith(...)的返回值就是回调函数的返回值。测试也验证了这一点test/src/stub-test.jsconst stub sinon.stub().callsArgWith(0, test); const callback sinon.stub().returns(return value); stub(callback); // return value组合用法与 onCall、callThrough 配合callsArgWith返回 stub 本身可与其他行为链式组合实现“不同调用次数执行不同行为”const stub sinon.stub(); stub .onFirstCall().callsArgWith(0, first) // 第 1 次调用回调收到 first .onSecondCall().callsArgWith(1, a, b) // 第 2 次调用取第 1 个参数作回调 .onThirdCall().callsArgOn(2, context); // 第 3 次调用指定回调 this const spy sinon.spy(); stub(spy); // spy 收到 first stub(1, spy); // spy 收到 a, b该组合场景同样有源码测试覆盖test/src/stub-test.js。此外callsArgWith会覆盖先前设置的callThrough内部将callsThrough置为false测试见 test/src/stub-test.jsconst stub sinon.stub(obj, fn).callThrough().callsArgWith(0, test); const callback sinon.stub().returns(return value); stub(callback); // 不再穿透调用 obj.fn而是调用 callback异步版本callsArgWithAsync如需回调异步触发在下一次 tick 中执行可使用 stub.callsArgWithAsync。它并非独立实现而是由 src/sinon/util/core/export-async-behaviors.js 自动生成对名称匹配/^(callsArg|yields)/且不含Async的方法生成同名Async版本仅将callbackAsync置为true其余逻辑完全复用同步版本。同步版本内部通过nextTick调度保证回调不会在当前调用栈内同步执行const stub sinon.stub().callsArgWithAsync(0, result); let called false; stub(() { called true; }); called; // false —— 回调尚未执行已调度到下一个 tickcallsArgWith 与 callsArg 系列方法选型对照callsArgWith属于以“指定索引取回调”为核心的callsArg方法族下表梳理了各成员与本文方法的差异方法回调位置回调实参回调this触发时机stub.callsArg指定index无undefined同步stub.callsArgWith指定index自定...argsundefined同步stub.callsArgOn指定index无指定context同步stub.callsArgOnWith指定index自定...args指定context同步stub.callsArgAsync指定index无undefined下一 tickstub.callsArgWithAsync指定index自定...argsundefined下一 tickstub.callsArgOnAsync指定index无指定context下一 tickstub.callsArgOnWithAsync指定index自定...args指定context下一 tick选型建议当回调需要接收固定参数如 error-first 回调的(err, data)时callsArgWith是首选若还需控制回调内部的this则升级为callsArgOnWith若回调不需要任何参数直接用更简洁的callsArg即可。若回调位置不固定、希望自动寻找参数列表中最左/最右的函数则应改用yields/yieldsRight家族参见 stubs 概念文档 与 stub.yields。小结stub.callsArgWith(index, ...args)是 Sinon 中“以参数位置定位回调、以固定实参驱动回调”的标准工具其核心价值在于在不执行真实依赖的前提下精确控制回调的触发时机与入参从而稳定驱动被测代码的回调分支。使用时牢记三点index必须是数字配置期抛TypeError、实参数量必须超过index调用期抛TypeError、该位置实参必须是函数调用期抛TypeError它同步触发回调、返回值为回调的返回值可放心与onCall链式组合构建多阶段行为。完整的 Stub API 列表可查阅 Stub API 索引更深入的行为机制可阅读 src/sinon/default-behaviors.js 与 src/sinon/behavior.js。赞分享测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载相关推荐SpacetimeDB Unreal SDK Types 目录深度解析从 ClientAPI 线协议镜像到 UE 值类型桥接SpacetimeDB Unreal SDK Types 目录深度解析从 ClientAPI 线协议镜像到 UE 值类型桥接 本篇技术指南以 sdks/unr测试开发工具Sinon stub.callArg 深入解析按索引精准触发 stub 回调函数Sinon stub.callArg 深入解析按索引精准触发 stub 回调函数 stub.callArg index 是 Sinon 中用于“主动触发”st测试开发工具Sinon 深入stub.callsArgOnAsync —— 异步触发指定参数回调并绑定 this 上下文Sinon 深入stub.callsArgOnAsync —— 异步触发指定参数回调并绑定 this 上下文 stub.callsArgOnAsync ind测试开发工具上一篇Zwift-Offline项目在macOS上解决Docker端口冲突问题下一篇ComfyUI-Easy-Use 插件兼容性问题分析与解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Buildah 仓库中的 go-zfs 库深度解析:ZFS 命令行 Go 封装与 ZFS 存储驱动实现

Buildah 仓库中的 go-zfs 库深度解析:ZFS 命令行 Go 封装与 ZFS 存储驱动实现

云原生 【免费下载链接】buildah A tool that facilitates building OCI images. 项目地址: https://gitcode.com/gh_mirrors/bu/buildah 点击查看 免费下载 本文以 Buildah 仓库中 vendor 的 go-zfs/v4 库说明文档为骨架,系统讲解这个 ZFS 命令行工具的…

2026/9/25 5:31:26 阅读更多 →
Security-101 零信任入门:验证每一次访问请求

Security-101 零信任入门:验证每一次访问请求

Security-101 零信任入门:验证每一次访问请求 【免费下载链接】Security-101 8 Lessons, Kick-start Your Cybersecurity Learning. 项目地址: https://gitcode.com/GitHub_Trending/se/Security-101 零信任是安全圈的高频词,但多数人只把它当口号…

2026/9/25 5:30:26 阅读更多 →
Windows下速腾激光雷达点云调试与Wireshark抓包实战指南

Windows下速腾激光雷达点云调试与Wireshark抓包实战指南

/* 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 5:30:26 阅读更多 →

最新新闻

Design Compiler:Topographical Workshop Lab4

Design Compiler:Topographical Workshop Lab4

相关阅读 Design Compilerhttps://blog.csdn.net/weixin_45791458/category_12738116.html?spm1001.2014.3001.5482 目录 实验四、拥塞(实验时长:30分钟) 学习目标 任务一、将已编译的网表读取到DC-T中 任务二、使用文本报告分析拥塞 任务三…

2026/9/25 7:35:55 阅读更多 →
Python采集中国天气网天气数据:JSON接口与城市ID实战

Python采集中国天气网天气数据:JSON接口与城市ID实战

/* 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 7:35:55 阅读更多 →
Python入门实战:猜数字游戏完整开发教程

Python入门实战:猜数字游戏完整开发教程

/* 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 7:35:54 阅读更多 →
Claude Code + TaoToken + GLM-4.1V-Thinking:视觉Agent评测环境搭建实战

Claude Code + TaoToken + GLM-4.1V-Thinking:视觉Agent评测环境搭建实战

1. 为什么我要折腾这套视觉 Agent 评测环境先说清楚这套东西到底在干什么。Claude Code是 Anthropic 推出的命令行编程助手,能在终端里直接读写文件、跑命令、调工具,本质上是一个带工具调用能力的 Agent 运行时。TaoToken在这里扮演的是模型接入层&…

2026/9/25 7:35:54 阅读更多 →
FPGA MicroBlaze Bootloader实现指南:从启动原理到Flash固化与OTA升级

FPGA MicroBlaze Bootloader实现指南:从启动原理到Flash固化与OTA升级

/* 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 7:35:54 阅读更多 →
Atlas 300V 24G推理卡跑YOLO:从环境搭建到部署调优全指南

Atlas 300V 24G推理卡跑YOLO:从环境搭建到部署调优全指南

1. 一台推理卡,为什么值得单独写一篇先说结论:Atlas 300V 24G是华为昇腾生态里一款纯推理场景的加速卡,目标对象非常明确——跑YOLO这类检测模型,做视频流分析、边缘智能、工业质检、园区安防等任务。很多刚接触昇腾的人会被一堆名…

2026/9/25 7:34:54 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →