测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载assert.neverCalledWith是 Sinon 内置断言集合docs/concepts/assertions/api/index.md中用于“否定式参数断言”的核心方法它要求传入的fake、spy或stub从未以给定参数组合被调用过。本文以该 API 的官方文档为主体结合仓库源码与测试用例讲解其语义、用法、错误信息格式、底层实现原理并延伸介绍支持sinon.match匹配器的neverCalledWithMatch变体帮助你在单元测试中写出更严谨的“负向校验”断言。断言语义与calledWith正好相反sinon.assert.neverCalledWith(spy, arg1, arg2, ...)的语义非常明确只要目标 fake/spy/stub 从未以arg1, arg2, ...这一组参数被调用过断言即通过一旦存在一次参数完全相等的调用断言即失败并抛出AssertError。它与正向断言calledWith见 docs/concepts/assertions/api/called-with.md构成互补关系calledWith(spy, arg1, ...)至少一次以指定参数调用 → 通过neverCalledWith(spy, arg1, ...)一次都没有以指定参数调用 → 通过。需要特别注意的是neverCalledWith判断的是“从未以这组参数调用”而非“从未被调用”。即使目标 fake 被调用了很多次只要没有任何一次调用的参数与断言给出的参数完全一致断言依旧通过。这一区别在后续示例中会反复体现。基本用法与官方示例官方文档给出的最小示例ES Module 导入方式import * as sinon from sinon; const fake sinon.fake(); // Generates no error sinon.assert.neverCalledWith(fake, apple pie); fake(apple pie); sinon.assert.neverCalledWith(fake, apple pie); // Uncaught: Error [AssertError]: expected fake to never be called with arguments apple pie // Generates no error sinon.assert.neverCalledWith(fake, lemon meringue pie);逐行拆解这段代码的执行过程sinon.fake()创建一个全新的 fake 函数尚未被调用此时neverCalledWith(fake, apple pie)通过——fake 没有任何调用记录自然不可能以apple pie被调用过fake(apple pie)制造一次调用参数为apple pie再次执行neverCalledWith(fake, apple pie)由于已经存在一次参数完全匹配的调用断言失败抛出Error [AssertError]错误消息为expected fake to never be called with arguments apple pie最后一次断言换用从未出现过的参数lemon meringue pie因为没有任何一次调用使用该参数断言通过不抛任何错误。从第 2 步与第 5 步可以提炼出该断言的两种典型通过场景目标从未被调用调用记录为空目标被调用过但没有任何一次调用的参数与断言参数完全相等。变体neverCalledWithMatch基于匹配器的否定断言官方文档还提供了neverCalledWith的匹配器变体sinon.assert.neverCalledWithMatch(spy, arg1, arg2, ...)见 docs/concepts/assertions/api/never-called-with-match.md。其语义为目标从未以“匹配给定参数”的调用出现过即不存在任何一次调用其每个实参都能分别匹配断言给出的参数断言参数可以是精确值也可以是sinon.match匹配器。官方文档明确指出它的行为等价于sinon.assert.neverCalledWith( spy, sinon.match(arg1), sinon.match(arg2), ... );也就是说精确值比较被替换成了匹配器比较其余否定逻辑完全一致。官方示例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这个例子展示了两个关键点部分匹配即可触发失败fake({ name: apple pie, price: 123 })传入的实参对象比期望对象{ name: apple pie }多出price属性但neverCalledWithMatch做的是“匹配”而非“全等比较”因此该调用命中了期望断言失败错误消息附带完整调用历史失败信息不仅说明“期望 fake 从未以 match { name: apple pie } 被调用”还逐行列出了所有相关调用记录cherry pie与apple pie两次调用方便快速定位是哪一次调用破坏了断言。在测试框架中实际使用官方文档在“Example using test framework”一节中直接引入了仓库内的测试用例文件原文档指向../../../.vitepress/tests/...该路径在发布构建中生效本仓库中的实际文件位于 docs/tests/docs/assertions/api/never-called-with.test.js使用tap编写import tap from tap; import * as sinon from sinon; tap.test( assert.neverCalledWith - passes when not called with arguments, (t) { const fake sinon.fake(); fake(apple); t.doesNotThrow(() { sinon.assert.neverCalledWith(fake, banana); }, assertion should pass); t.end(); } ); tap.test(assert.neverCalledWith - fails when called with arguments, (t) { const fake sinon.fake(); fake(apple); t.throws( () sinon.assert.neverCalledWith(fake, apple), /expected fake to never be called with arguments/, assertion should fail when called with specified arguments ); t.end(); });这里演示了在测试框架中验证断言的两种标准姿势通过场景用t.doesNotThrow(...)包裹断言验证“参数不匹配时不抛错”失败场景用t.throws(...)包裹断言并用正则/expected fake to never be called with arguments/校验错误消息内容从而同时验证“失败发生”与“失败原因符合预期”。neverCalledWithMatch的测试用例docs/tests/docs/assertions/api/never-called-with-match.test.js还额外覆盖了“传入sinon.match.string等匹配器时不匹配”的通过场景以及“对象部分字段匹配即失败”的失败场景可作为补充参考// 匹配器不匹配 → 通过 const fake sinon.fake(); fake(123); t.doesNotThrow(() { sinon.assert.neverCalledWithMatch(fake, sinon.match.string); }, assertion should pass when matcher doesnt match); // 部分字段匹配 → 失败 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 );错误消息的完整格式与AssertError从仓库源码看neverCalledWith与neverCalledWithMatch的失败消息模板定义在 src/sinon/assert.jsmirrorPropAsAssertion( neverCalledWith, expected %n to never be called with arguments %*%C, ); mirrorPropAsAssertion( neverCalledWithMatch, expected %n to never be called with match %*%C, );其中%n、%*、%C是 Sinon 的 printf 格式化占位符由 fake/spy 的printf方法在拼接消息时替换%n被断言对象的名字如fake、doSomething%*展开剩余的断言参数列表%C该对象全部调用的格式化列表即错误消息末尾附带的调用历史。实际抛出的错误对象由assert.fail构造其name被显式设置为AssertError见 src/sinon/assert.jsfail: function fail(message) { let msg message; if (cleanedAssertOptions.shouldLimitAssertionLogs) { msg message.substring(0, cleanedAssertOptions.assertionLogLimit); } const error new Error(msg); error.name AssertError; throw error; },因此你在测试运行器或浏览器控制台中看到的失败对象是Error [AssertError]可以直接通过error.name AssertError进行类型判断也可以通过createAssertObject的shouldLimitAssertionLogs/assertionLogLimit选项默认false/10000控制超长调用历史日志是否截断。仓库的单元测试 test/src/assert-test.js 精确锁定了两个 API 的最终消息格式// neverCalledWith expected doSomething to never be called with arguments 1, 2 doSomething(1, 2, 3) // neverCalledWithMatch expected doSomething to never be called with match 1, 2 doSomething(1, 2, 3)即“主消息 换行 缩进的调用记录”其中调用记录doSomething(1, 2, 3)就是%C被替换后的产物。有了这份格式约定你在测试中就可以用稳定、精确的正则或字符串断言去匹配错误内容而不是依赖易变的文案细节。底层实现原理mirrorPropAsAssertion的否定逻辑neverCalledWith并不是手写的独立函数而是通过 src/sinon/assert.js 中的mirrorPropAsAssertion(name, message)工厂函数自动生成的一族断言之一function mirrorPropAsAssertion(name, method, message) { ... assert[name] function (fake) { verifyIsStub(fake); const args arraySlice(arguments, 1); let failed false; verifyIsValidAssertion(name, args); if (typeof meth function) { failed !meth(fake); } else { failed typeof fake[meth] function ? !fake[meth].apply(fake, args) : !fake[meth]; } if (failed) { failAssertion( this, (fake.printf || fake.proxy.printf).apply( fake, concat([msg], args), ), ); } else { assert.pass(name); } }; }以neverCalledWith为例其生成的断言执行流程是verifyIsStub(fake)校验先确认传入的第一个参数确实是 Sinon 代理对象fake/spy/stub。从源码看该校验会检查method.getCall是否为函数并支持method.proxy.isSinonProxy的递归判定见 src/sinon/assert.js不合法时抛出fake is not a spy或is not stubbed提取参数arguments中除第一个被断言对象之外的全部参数即断言参数列表求值调用fake.neverCalledWith(...)底层方法取反后赋给failed——neverCalledWith的底层语义恰好是“没有任何一次调用匹配参数”断言逻辑即其直接复用判定failed为真时通过failAssertion抛出AssertError消息由fake.printf(msg, ...args)按%n/%*/%C占位符渲染否则调用assert.pass(name)静默通过。由此可以推断neverCalledWith系列断言的正确性完全建立在 fake/spy 底层neverCalledWith方法的实现之上二者语义一一对应mirrorPropAsAssertion只负责“取反 格式化错误消息 参数合法性校验”这三件事。实用建议与注意事项综合官方文档与源码实现使用neverCalledWith/neverCalledWithMatch时有几点值得注意它是“参数否定”而非“调用否定”需要“从未被调用过”时应使用notCalled见 docs/concepts/assertions/api/not-called.md需要“从未以某参数调用”时才使用neverCalledWith。两者关注点不同不要混用。精确比较 vs 匹配比较neverCalledWith使用 samsam 的深度相等比较实参须与断言参数完全相等才视为命中neverCalledWithMatch则允许断言参数为sinon.match匹配器或“部分字段匹配”的对象命中范围更宽适合校验“含有敏感字段的对象不该出现”这类场景。匹配器用法neverCalledWithMatch(fake, sinon.match.string)可以断言“从未以字符串参数被调用”也可组合sinon.match.object、sinon.match.has(...)等匹配器构造复杂约束匹配器全集见 docs/concepts/matchers/index.mdmatch断言见 docs/concepts/assertions/api/match.md。失败消息可断言AssertError的消息格式主消息 调用历史已被单元测试锁定测试中可用正则或includes校验失败原因提升失败可诊断性。前置校验会先行拦截错误输入传入非 Sinon 代理对象如普通函数、null时断言会在求值前抛出不带格式化消息的失败因此不要用该断言去“测试”普通函数它只适用于 fake/spy/stub。参考链接断言 API 索引docs/concepts/assertions/api/index.md本 API 官方文档docs/concepts/assertions/api/never-called-with.md匹配器变体文档docs/concepts/assertions/api/never-called-with-match.md底层实现src/sinon/assert.js仓库测试用例docs/tests/docs/assertions/api/never-called-with.test.js、docs/tests/docs/assertions/api/never-called-with-match.test.js核心单元测试消息格式锁定test/src/assert-test.js赞分享测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载相关推荐ONNX Runtime Stable Diffusion GPU 优化实战从 ONNX 导出、融合优化到 CUDA/TensorRT 推理与基准测试ONNX Runtime Stable Diffusion GPU 优化实战从 ONNX 导出、融合优化到 CUDA/TensorRT 推理与基准测试 本文以测试开发工具SingleFile完整指南如何一键保存完整网页到单个HTML文件SingleFile完整指南如何一键保存完整网页到单个HTML文件 在信息时代我们每天都会遇到需要保存的宝贵网页内容——研究资料、技术文档、新闻文章或是值测试开发工具5个Windows风扇控制难题FanControl免费解决方案终极指南5个Windows风扇控制难题FanControl免费解决方案终极指南 还在为电脑风扇噪音而烦恼吗Windows系统自带的散热控制总是无法满足需求要么太吵测试开发工具上一篇如何在5分钟内快速上手MCP Toolbox for Databases新手终极指南下一篇如何用Python和Web技术构建跨平台桌面应用5个核心问题解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
1999-2025年上市公司绿色持续创新水平数据+代码 一、数据介绍
数据名称:上市公司绿色持续创新水平
数据范围:企业层面
时间范围:1999-2025年
样本数量:156760条
数据来源:国家知识产权局
数据说明:含原始数据、计算代码、计算结果
二、数据指标 图… · 2026/9/24 20:58:26
AI小说生成实测:只给一个主题,能写出10万字的长篇小说吗? AI小说生成实测:只给一个主题,能写出10万字的长篇小说吗? 【免费下载链接】AI_NovelGenerator 使用ai生成多章节的长篇小说,自动衔接上下文、伏笔 项目地址: https://gitcode.com/GitHub_Trending/ai/AI_NovelGenerator
脑… · 2026/9/24 20:58:19
幂等性设计实战:保障分布式系统数据一致性的四大模式 1. 幂等性不是玄学,是系统稳定性的底层锚点“什么是幂等性?”——这问题我每天至少被问三遍,不是在技术评审会上,就是在帮业务方排查线上故障的深夜电话里。它不像“高并发”“分布式事务”那样自带光环,却像空气一样无… · 2026/9/24 20:58:13
告别Miscellaneous:打造个人杂项收集与归档系统的实操指南 前阵子整理硬盘和学习笔记时,我发现自己散落着大量“不知道放哪、但又不能删”的东西。一张截图、一段摘抄、一份临时文档、一个随手记下的灵感,它们全都被塞进了一个叫“Miscellaneous”的文件夹里。结果不到两个月,这个文件夹就变成了一座垃… · 2026/9/24 21:33:16
告别杂项黑洞:从Miscellaneous到高效信息整理的完整实践 我做了快十年的内容与信息管理,电脑里最不敢打开的就是那个名为“Miscellaneous”的文件夹。它像一个黑洞,吞掉所有暂时不知道往哪里放的东西:随手截的图、半年前的合同扫描件、突然灵光一闪的构思草稿、下载完就再也没碰过的软件安装包。每次… · 2026/9/24 21:33:16
Python多进程+多线程并发处理Redis与Kafka数据实战 我最早写这个脚本的场景,其实特别朴素:业务方丢过来一堆需求,要从Redis的队列里捞数据做清洗,再从Kafka的topic里消费一批日志做指标统计,而且数据量不小,单机跑一条线程根本吃不完。试过先写脚本串行跑&am… · 2026/9/24 21:33:16
宁夏口碑好的央国企职业规划机构选择指南 在宁夏打算求职央国企,想要找靠谱的职业规划机构应该怎么选?这是很多打算进入央国企发展的宁夏大学生,都会反复搜索的问题。央国企素来以稳定的薪资、完善的福利保障,成为应届毕业生求职的热门方向,不少同学从大一开始就筹备求职… · 2026/9/24 21:33:16
STM32 自学笔记 02 # GPIO
#软件平台 STM32CubeIde#软件包 STM32Cube_FW_F0_V1.11.6#系统平台 Win7初始化:void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();__HAL_RCC_GPIO… · 2026/9/24 21:33:16
Claude Opus 5.5 深度解析:旗舰能力、定价革命与国内接入实战指南 摘要2026 年 9 月 22 日,Anthropic 正式发布 Claude Opus 5.5,作为 Claude 5.5 系列的首款旗舰模型,它在多数工作任务上达到顶级旗舰 Claude Fable 5.1 的水平,在智能体编码、计算机操作、知识工作等多项基准测试中全面领先。更值… · 2026/9/24 21:33:10
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44