ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Sinon 中 stub.callsArgWith 深度解析:按参数索引触发回调并传入指定实参

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),仅供参考
返回列表