恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Sinon 断言 `assert.neverCalledWithMatch` 深入解析:验证 fake/spy/stub 从未以“匹配”参数被调用

  • 首页
  • 资讯中心
  • /
  • Sinon 断言 `assert.neverCalledWithMatch` 深入解析:验证 fake/spy/stub 从未以“匹配”参数被调用

相关资讯

AI技能版本管理实战:用Skillbox锁定Agent行为可复现性 2026/9/24 20:19:03
SeaORM 迁移器 CLI 实战指南:从 generate 到 fresh/refresh/reset 的完整命令手册 2026/9/24 20:19:03
C盘飘红怎么清理?7款免费磁盘清理扫描工具推荐与实操指南 2026/9/24 20:19:03

最新资讯

Java课程设计实战:泡泡糖游戏开发与Swing碰撞检测详解
Python与卷积神经网络的人脸表情识别实战:数据处理与训练避坑指南
YOLO捕鱼识别数据集实战:标签格式、训练配置与避坑指南
JavaFX自动化测试实战:工具选型、事件机制与混合分层策略
OpenClaw零密钥部署:用IAM临时凭证接入Bedrock
AI推理网关路由架构与策略实践:应对多模型调用混乱

今日推荐

JavaWeb购物车系统实现:基于Session存储的完整工程示例
面向对象综合训练:从图书管理系统掌握封装、继承与多态
Lombok与JDK版本冲突引发NoSuchFieldError:根因排查与修复指南

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Sinon 断言 `assert.neverCalledWithMatch` 深入解析:验证 fake/spy/stub 从未以“匹配”参数被调用

发布时间:2026/9/24 20:24:03
Sinon 断言 `assert.neverCalledWithMatch` 深入解析:验证 fake/spy/stub 从未以“匹配”参数被调用 Sinon 断言assert.neverCalledWithMatch深入解析验证 fake/spy/stub 从未以“匹配”参数被调用【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址: https://gitcode.com/gh_mirrors/si/sinonsinon.assert.neverCalledWithMatch(spy, arg1, arg2, ...)是 Sinon 内置断言 API 中的“否定 模糊匹配”组合用于验证一个fake、spy或stub从未以符合给定匹配条件partial match部分匹配的参数被调用。它适合在回调参数为对象、且你只关心其中几个字段时使用——例如确认某个副作用函数从未收到“类型为 Apple pie”的 payload。读完本文你将掌握该断言的语义、底层实现调用链、与严格匹配断言neverCalledWith的差异以及如何在测试框架中落地使用。API 签名与核心语义sinon.assert.neverCalledWithMatch(spy, arg1, arg2, ...);当spy这里的spy泛指 fake / spy / stub从未被“匹配”给定参数地调用时断言通过不抛错一旦存在任意一次调用满足匹配条件断言失败并抛出AssertError。该断言的官方定义明确给出了它与严格匹配断言之间的等价关系This behaves the same way assinon.assert.neverCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...)。也就是说neverCalledWithMatch本质上等价于把每个期望参数用sinon.match包裹后再调用sinon.assert.neverCalledWith。区别在于断言匹配方式典型场景neverCalledWith深度严格相等deepEqual期望参数完全精确时neverCalledWithMatchpartial match对象只要求包含指定属性且支持嵌套 matcher只关心参数的部分结构或类型特征时文档示例对象的 partial match官方文档给出了一个非常直观的示例——fake被调用过两次但只有第二次传入的对象包含了期望的name: apple pie属性import * as sinon from sinon; const fake sinon.fake(); const applePieExpectation { name: apple pie }; fake({ name: cherry pie, price: 123 }); // No match, no error :) sinon.assert.neverCalledWithMatch(fake, applePieExpectation); fake({ name: apple pie, price: 123 }); sinon.assert.neverCalledWithMatch(fake, applePieExpectation); // Uncaught: Error [AssertError]: expected fake to never be called with match { name: apple pie } // fake({ name: cherry pie, price: 123 }) at REPL10:1:1 // fake({ name: apple pie, price: 123 }) at REPL16:1:1注意两点partial match 语义第一次调用fake({ name: cherry pie, price: 123 })时参数对象里没有name: apple pie属性因此不构成匹配断言通过失败信息可读性第二次调用fake({ name: apple pie, price: 123 })包含了期望属性构成匹配断言抛出AssertError错误信息以expected fake to never be called with match { name: apple pie }开头并附上所有历史调用的日志%C调用记录方便定位是哪一次调用“污染”了断言。源码级实现断言如何落到每一次调用记录上neverCalledWithMatch并不是一个独立手写的断言而是通过源码中三个层次协作完成的1. 断言层mirrorPropAsAssertion镜像代理方法在 src/sinon/assert.js 中该断言由工厂函数mirrorPropAsAssertion生成mirrorPropAsAssertion( neverCalledWithMatch, expected %n to never be called with match %*%C, );mirrorPropAsAssertionsrc/sinon/assert.js的工作方式是先对传入的fake调用verifyIsStub校验其确为 spy/stub 代理然后把剩余参数透传给fake上的同名方法fake.neverCalledWithMatch(...)根据返回值判断成败失败时调用failAssertion抛出错误错误对象name被设置为AssertError见 src/sinon/assert.js。2. 代理层delegateToCalls把断言分发给每次调用在 src/sinon/proxy.js 中spy 代理对象通过delegateToCalls将neverCalledWithMatch委托给每次调用的notCalledWithMatch并提供一个默认回退delegateToCalls( proxyApi, neverCalledWithMatch, false, notCalledWithMatch, false, function () { return true; }, );delegateToCalls会把查询遍历到每一次spyCall上只要任意一次调用不匹配最终结果即失败而最后一个参数返回true的回退函数表示当 spy 从未被调用过时默认判定为“通过”——因为没有任何一次调用满足匹配这符合“never called with match”的字面语义。3. 调用记录层notCalledWithMatch取反calledWithMatch在 src/sinon/proxy-call.js 中单次调用记录上的实现非常简洁notCalledWithMatch: function notCalledWithMatch() { return !this.calledWithMatch.apply(this, arguments); },而calledWithMatchsrc/sinon/proxy-call.js是匹配的核心它逐一用samsam的createMatcher构造匹配器再对expectation.test(actual)做reduce聚合若期望参数个数多于实际调用参数个数直接判定不匹配。从源码结构看整条链路为assert.neverCalledWithMatch→fake.neverCalledWithMatch→ 逐次调用call.notCalledWithMatch→!call.calledWithMatch→sinon.match(expectation).test(actual)从而实现了“从未以匹配参数被调用”的判定。与sinon.match匹配器组合从“部分对象”到“任意复杂条件”由于neverCalledWithMatch等价于对每个参数套上sinon.match(...)它天然支持sinon.match的全部能力sinon.match(string)要求值是字符串且包含期望子串sinon.match(regexp)要求字符串匹配正则sinon.match(object)要求值非null/undefined且至少包含期望对象的全部属性支持嵌套匹配器{ id: sinon.match.number }sinon.match(function)使用自定义匹配器见 custom matchers以及sinon.match.any、sinon.match.array、sinon.match.number、sinon.match.string等内置类型匹配器完整列表见 matchers API。例如验证fake从未以“任意字符串”作为唯一参数被调用import * as sinon from sinon; const fake sinon.fake(); fake(123); // 123 不是字符串matcher 不匹配 → 断言通过 sinon.assert.neverCalledWithMatch(fake, sinon.match.string);这正是 docs/tests/docs/assertions/api/never-called-with-match.test.js 中第二个用例验证的场景。在测试框架中使用含完整测试用例文档中的示例测试对应仓库测试文件 docs/tests/docs/assertions/api/never-called-with-match.test.js使用tap编写覆盖了通过、matcher 不匹配、失败三种典型情况可直接复制到任意基于 Node 的测试环境import tap from tap; import * as sinon from sinon; tap.test( assert.neverCalledWithMatch - passes when not called with matching arguments, (t) { const fake sinon.fake(); fake({ name: Bob }); t.doesNotThrow(() { sinon.assert.neverCalledWithMatch(fake, { name: Alice }); }, assertion should pass); t.end(); } ); tap.test( assert.neverCalledWithMatch - passes with matcher that doesnt match, (t) { const fake sinon.fake(); fake(123); t.doesNotThrow(() { sinon.assert.neverCalledWithMatch(fake, sinon.match.string); }, assertion should pass when matcher doesnt match); t.end(); } ); tap.test( assert.neverCalledWithMatch - fails when called with matching arguments, (t) { const fake sinon.fake(); fake({ name: Alice, age: 30 }); t.throws( () sinon.assert.neverCalledWithMatch(fake, { name: Alice }), /expected fake to never be called with match/, assertion should fail when called with matching arguments ); t.end(); } );关键断言点用t.doesNotThrow验证“没有匹配调用”时断言静默通过用t.throws 正则/expected fake to never be called with match/验证失败场景的错误信息格式保证失败信息对调试者友好。如果你使用的是 Mocha / Jest / Vitest 等框架只需把t.doesNotThrow/t.throws换成对应框架的expect(...).not.toThrow()/expect(...).toThrow()即可断言本身与框架无关。失败时的错误信息与调试支持断言失败时抛出的错误具有两个对调试至关重要的特性错误类型错误对象名为AssertErrorerror.name AssertError见 src/sinon/assert.js方便在测试运行器中做统一的错误归类与展示消息内容格式串为expected %n to never be called with match %*%C其中%n替换为 spy 名称未命名时为fake%C展开为全部历史调用记录含每个调用发生的位置如文档示例中的at REPL10:1:1因此一旦断言失败你立刻能看到“是哪一次调用命中了匹配条件”。此外断言对象支持通过createAssertObject定制日志输出行为src/sinon/assert.jsshouldLimitAssertionLogs默认false与assertionLogLimit默认10000可用于在调用记录极多时截断错误消息避免终端被刷屏。与其他断言的对比与选择neverCalledWithMatch是 Sinon 断言家族“否定侧”的模糊匹配成员与它最常被一起权衡的兄弟方法有assert.neverCalledWith严格相等版本要求参数完全一致expected fake to never be called with arguments apple pie。当你不确定对象全部字段、只想盯住关键字段时应改用neverCalledWithMatchassert.calledWithMatch同一匹配语义的“肯定侧”版本并支持针对单个spyCall断言sinon.assert.calledWithMatch(spy.secondCall, arg1, ...)正向约束族calledOnceWithMatch恰好一次且匹配、alwaysCalledWithMatch所有调用均匹配与“从未匹配”构成完整的正向/负向覆盖spy 实例方法spy.neverCalledWithMatchspies API与单次调用记录的spyCall.notCalledWithMatchspy-call API——sinon.assert.neverCalledWithMatch底层正是复用这些方法并叠加断言校验与格式化错误消息。完整断言方法清单见 Assertions API 索引。最佳实践小结优先用于“防误入”类负向验证如“缓存回调绝不能被以type: internal的请求触发”“上报函数绝不能收到含name: apple pie的 payload”用 partial match 降低脆弱性对象参数带上price等无关字段的精确全量断言会让测试与实现过度耦合neverCalledWithMatch只关注必要字段失败信息即文档配合AssertError与调用记录输出断言失败时能直接从消息中定位命中匹配的具体调用与正向断言互补把calledWithMatch应发生与neverCalledWithMatch不应发生成对使用可完整刻画一个函数的参数契约。【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址: https://gitcode.com/gh_mirrors/si/sinon创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号