首页/新闻资讯/正文详情

Sinon `assert.calledOnceWithMatch` 断言完全指南:精确匹配一次调用

发布时间:2026/9/24 15:33:16 来源:云帆数科 栏目:资讯中心
Sinon `assert.calledOnceWithMatch` 断言完全指南:精确匹配一次调用
测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载本文基于 Sinon.JS 官方文档docs/concepts/assertions/api/called-once-with-match.md展开系统讲解assert.calledOnceWithMatch的语义、与calledOnceWithExactly的差异、与sinon.match的配合方式并结合仓库源码与测试用例深入其实现原理。读完本文你将能够在单元测试中准确验证“某个 fake/spy/stub 恰好被调用一次且参数与预期匹配”并学会如何解读其 AssertError 报错信息。一、API 速览与核心语义assert.calledOnceWithMatch是 Sinon 内置断言集合中的一个方法签名如下sinon.assert.calledOnceWithMatch(spy, arg1, arg2, ...)当fake、spy或stub恰好被调用一次且调用参数与给定的匹配条件相符时断言通过不产生任何错误否则抛出一个名为AssertError的错误。该断言是calledWithMatch与calledOnce两重约束的组合调用次数约束目标必须恰好被调用 1 次与 assert.calledOnce 一致参数匹配约束目标那次调用的实参必须与期望参数匹配与 assert.calledWithMatch 一致。这里的匹配并非严格相等而是部分匹配 / 子集匹配语义期望参数可以是对象的子集只要实际实参包含期望对象中列出的所有属性即可通过。其失败信息统一为expected %n to be called once and with match %D该消息定义于 src/sinon/assert.js其中%n会被替换为 fake/spy/stub 的名称%D会被替换为调用参数的格式化描述。二、基础用法与官方示例文档 docs/concepts/assertions/api/called-once-with-match.md 给出的核心示例直接复现了部分匹配的精髓import * as sinon from sinon; const fake sinon.fake(); const applePieExpectation { name: apple pie }; fake({ name: apple pie, price: 123 }); // Matches, generates no error sinon.assert.calledOnceWithMatch(fake, applePieExpectation); fake({ name: apple pie, price: 123 }); sinon.assert.calledOnceWithMatch(fake, applePieExpectation); // Uncaught Error [AssertError]: expected fake to be called once and with match // Call 1: // { name: apple pie, price: 123 } { name: apple pie } // Call 2: // { name: apple pie, price: 123 } { name: apple pie }要点解读第一次调用fake({ name: apple pie, price: 123 })后断言期望对象{ name: apple pie }是实际实参{ name: apple pie, price: 123 }的子集因此部分匹配成功不抛错。第二次调用之后目标被调用了两次不再满足called once约束断言抛出AssertError。错误消息会逐个列出每一次调用的实际参数与期望参数{ name: apple pie, price: 123 } { name: apple pie }帮助你快速定位是哪一次调用、哪一个参数不匹配。三、匹配语义详解为什么是match而不是exact要正确使用calledOnceWithMatch必须区分它与两个相近断言断言方法调用次数要求参数要求assert.calledOnce恰好 1 次不检查参数assert.calledOnceWith恰好 1 次参数浅相等deepEqual语义assert.calledOnceWithExactly恰好 1 次参数完全相等且数量一致assert.calledOnceWithMatch恰好 1 次参数部分匹配支持嵌套匹配器在 src/sinon/proxy.js 中可以看到calledOnceWithMatch是通过delegateToCalls基于calledWithMatch构建的delegateToCalls( proxyApi, calledOnceWithMatch, true, calledWithMatch, false, undefined, 1, );最后一个参数1即要求调用次数恰好为 1。而calledWithMatch的匹配逻辑最终委托给samsam的createMatcher见 src/sinon/assert.js该库实现了 Sinon 的深度部分匹配算法对对象实际值不能是null/undefined且必须包含期望对象声明的所有属性允许有额外属性对嵌套对象支持递归匹配即匹配器可以嵌套使用对数字要求实参期望值宽松相等对字符串要求实参是字符串且包含期望子串对正则要求实参是字符串且能被正则匹配。因此assert.calledOnceWithMatch非常适合我不关心对象的所有字段只关心关键字段的测试场景例如只校验接口响应中的id、name等关键字段而不必写出完整的期望对象。四、与sinon.match的配合嵌套匹配器assert.calledOnceWithMatch支持传入sinon.match匹配器作为期望参数从而实现更精细的断言。sinon.match的完整能力见 docs/concepts/matchers/api/match.md常用形式包括import * as sinon from sinon; const fake sinon.fake(); fake({ name: apple pie, price: 123, tags: [dessert, sweet] }); // 期望对象 嵌套匹配器 sinon.assert.calledOnceWithMatch(fake, { name: apple pie, price: sinon.match.number, // 要求 price 是数字 tags: sinon.match.array // 要求 tags 是数组 }); // 直接使用匹配器作为整个期望参数 sinon.assert.calledOnceWithMatch(fake, sinon.match.object);与assert.calledWithMatch(spy, sinon.match(arg1), ...)等价参见 assert.calledWithMatch 文档说明calledOnceWithMatch在部分匹配的基础上叠加了恰好一次的约束非常适合验证某个副作用只被触发一次且入参符合预期的场景例如支付接口被调用一次且入参中金额字段符合正则埋点上报被调用一次且事件名与附加属性匹配外部 SDK 初始化被调用一次且配置对象包含关键字段。五、在测试框架中使用官方测试示例官方文档通过 VitePress 测试嵌入指令展示了在测试框架中的真实用法。对应文件为 docs/tests/docs/assertions/api/called-once-with-match.test.js使用 Node 生态常用的tap测试运行器import tap from tap; import * as sinon from sinon; tap.test( assert.calledOnceWithMatch - passes when called once with matching arguments, (t) { const fake sinon.fake(); fake({ name: Alice, age: 30 }); t.doesNotThrow(() { sinon.assert.calledOnceWithMatch(fake, { name: Alice }); }, assertion should pass); t.end(); } ); tap.test(assert.calledOnceWithMatch - fails when called twice, (t) { const fake sinon.fake(); fake({ name: Alice }); fake({ name: Alice }); t.throws( () sinon.assert.calledOnceWithMatch(fake, { name: Alice }), /expected fake to be called once/, assertion should fail when called more than once ); t.end(); }); tap.test( assert.calledOnceWithMatch - fails with non-matching arguments, (t) { const fake sinon.fake(); fake({ name: Bob }); t.throws( () sinon.assert.calledOnceWithMatch(fake, { name: Alice }), /expected fake to be called once/, assertion should fail with non-matching arguments ); t.end(); } );该测试用例覆盖了三条核心路径可以作为你在 Jest / Mocha / Vitest 等框架中迁移的参考通过路径调用一次且参数部分匹配 →doesNotThrow次数失败路径调用两次 → 抛出包含expected fake to be called once的错误参数失败路径调用一次但参数不匹配{ name: Bob }vs{ name: Alice }→ 抛出错误。在任何测试框架中使用时若断言失败抛出的AssertError无法被框架识别为断言错误可通过 assert.fail、assert.expose 与 assert.pass 自定义失败/成功钩子使其与框架集成参见 docs/concepts/assertions/index.md 的 Integrations 一节。六、spy 对象上的同构方法spy.calledOnceWithMatch在介绍断言之外值得一提的是calledOnceWithMatch同时也是 spy 实例上的一个直接方法二者语义一致。spy 版本返回布尔值true/false而assert版本在失败时抛出详细错误。在 test/src/spy-test.js 中测试明确验证了 spy 版本的行为边界describe(.calledOnceWithMatch, function () { beforeEach(function () { this.spy createSpy(); }); it(returns true for exact match, function () { this.spy(1, 2, 3); assert.isTrue(this.spy.calledOnceWithMatch(1, 2, 3)); }); it(returns true for partial match, function () { this.spy(1, 2, 3); assert.isTrue(this.spy.calledOnceWithMatch(1, 2)); }); it(returns false for exact parameters but called more then once, function () { this.spy(1, 2, 3); this.spy(1, 2, 3); assert.isFalse(this.spy.calledOnceWithMatch(1, 2, 3)); }); it(return false for one mismatched call, function () { this.spy(1, 2); assert.isFalse(this.spy.calledOnceWithMatch(1, 2, 3)); }); it(return false for one mismatched call with some other, function () { this.spy(1, 2, 3); this.spy(1, 2); assert.isFalse(this.spy.calledOnceWithMatch(1, 2, 3)); }); });由此可以总结出 spy 版本calledOnceWithMatch的四条判定规则只调用一次且实参完全匹配期望 →true只调用一次实参为期望的超集部分匹配→true调用超过一次即使每次参数都完全匹配→false某次调用的实参无法匹配期望 →false。注意第 4 条中的边界情况即使目标被调用两次其中一次完全匹配、另一次不匹配如最后一条测试spy(1, 2, 3)与spy(1, 2)混合结果依然为false因为恰好一次要求所有调用都必须满足匹配条件。对应地assert.calledOnceWithMatch的失败消息格式为expected %n to be called once and with match %D其定义位置在 src/sinon/assert.js与 spy 方法共享相同的判定逻辑区别仅在于失败时抛出AssertError而非返回false。七、断言错误信息解读当断言失败时AssertError会提供丰富的调试信息。以文档示例为基准错误输出格式为Uncaught Error [AssertError]: expected fake to be called once and with match Call 1: { name: apple pie, price: 123 } { name: apple pie } Call 2: { name: apple pie, price: 123 } { name: apple pie }每一行Call N:之后列出的是该次调用的实际实参与期望参数的对比。当有多次调用时逐条列出可以立即看出是哪一次调用不匹配在部分匹配语义下这里显示的不匹配通常是因为次数超过 1 而整体失败实际参数与期望参数在结构上的差异。从源码结构看错误消息中的%D占位符由assert内部的格式化逻辑替换为实际调用参数调用次数信息则由delegateToCalls传入的调用计数第 7 个参数1驱动src/sinon/proxy.js因此无论是 assert 版本还是 spy 版本失败信息都能精确反映次数 参数两个维度的问题。八、实践建议与常见误区明确区分 match 与 exactly如果业务上要求参数一字不差包括属性数量一致请使用 assert.calledOnceWithExactly只有当你需要容忍额外字段、只关心关键字段时才使用calledOnceWithMatch。善用部分匹配减少脆弱断言对包含时间戳、随机 ID、动态金额的对象直接写完整期望对象会导致测试频繁因无关字段变化而失败用calledOnceWithMatchsinon.match可以显著降低测试脆弱性。次数约束是硬性条件即使每次调用的参数都匹配只要调用次数不是恰好一次断言依然失败——这与calledWithMatch不限制次数有本质区别。集成测试框架时配置 fail/exposeAssertError默认是普通Error如需与 Jest/Chai 等框架的断言机制无缝衔接应参考 docs/concepts/assertions/index.md 自定义sinon.assert.fail。参考资料本文主体文档docs/concepts/assertions/api/called-once-with-match.md断言 API 索引docs/concepts/assertions/api/_index.md断言总览与框架集成docs/concepts/assertions/index.md相近断言assert.calledOnce、assert.calledOnceWithExactly、assert.calledWithMatch匹配器说明docs/concepts/matchers/api/match.md实现源码src/sinon/assert.js、src/sinon/proxy.js单元测试test/src/spy-test.js、docs/tests/docs/assertions/api/called-once-with-match.test.js赞分享测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载相关推荐GalGame翻译工具LunaTranslator实战教程3种提取模式跑通第一条译文GalGame翻译工具LunaTranslator实战教程3种提取模式跑通第一条译文 如果你在玩日文GalGame时卡在语言关LunaTranslator是测试开发工具Sinon Matchers API 完全指南用 sinon.match 实现灵活精确的参数匹配与断言Sinon Matchers API 完全指南用 sinon.match 实现灵活精确的参数匹配与断言 导读 Sinon 的 Matchers匹配器是测试测试开发工具Sinon assert.callCount 详解精确断言 fake/spy/stub 的调用次数Sinon assert.callCount 详解精确断言 fake/spy/stub 的调用次数 sinon.assert.callCount spy, n测试开发工具上一篇学术排版效率工具天津大学LaTeX模板的规范兼容解决方案下一篇WzComparerR2重新定义冒险岛WZ文件解析与资源提取技术创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Yii 2 框架核心包(yiisoft/yii2)安装指南与框架结构解析
Yii 2 框架核心包(yiisoft/yii2)安装指南与框架结构解析

后端Web框架 【免费下载链接】yii2 Yii 2: The Fast, Secure and Professional PHP Framework 项目地址: https://gitcode.com/gh_mirrors/yi/yii2 点击查看 免费下载 Yii 2 是目前 Yii 框架家族中应用最广的稳定版本,其核心框架代码以 yiisoft/yii2 包… · 2026/9/24 15:33:16

OpenLayers 6.4.1 补丁版本解析:回归修复与源码级原理剖析
OpenLayers 6.4.1 补丁版本解析:回归修复与源码级原理剖析

前端GIS数据可视化 【免费下载链接】openlayers OpenLayers 项目地址: https://gitcode.com/gh_mirrors/op/openlayers 点击查看 免费下载 6.4.1 是 OpenLayers 在 6.4.0 大版本发布后推出的纯缺陷修复版本(bugfix release),核心… · 2026/9/24 15:33:16

**SW凸轮槽的精确建模方法**
**SW凸轮槽的精确建模方法**

在调焦结构中,经常用到圆柱凸轮槽的结构,如下图所示,关于该凸轮槽的建模方法,有直接切除、包覆、扫描切除等方法,本文对这几种方法进行讨论,并最终确定扫描切除的精确方法 图1图1常见调焦凸轮结构在讨论之前… · 2026/9/24 15:33:09

mcp-use TypeScript 全栈 MCP 框架实战:构建 Agent、MCP Server 与跨客户端 MCP Apps
mcp-use TypeScript 全栈 MCP 框架实战:构建 Agent、MCP Server 与跨客户端 MCP Apps

后端MCP 服务MCP ClientsAI Agent人工智能 【免费下载链接】mcp-use The fullstack MCP framework to develop MCP Apps for ChatGPT / Claude & MCP Servers for AI Agents. 项目地址: https://gitcode.com/gh_mirrors/mc/mcp-use 点击查看 免费下载 mcp-use … · 2026/9/24 16:05:59

62.qt quick-QML虚拟软键盘V2版本(手机键盘弹出机制)-支持换肤、动态加载移除语言、发布linux软键盘程序、支持qt6
62.qt quick-QML虚拟软键盘V2版本(手机键盘弹出机制)-支持换肤、动态加载移除语言、发布linux软键盘程序、支持qt6

最新版本已更新,请用最新版本: 108.qt quick-QML虚拟软键盘V3版本-新增点击空白区域收回键盘、支持ListView、Flickable自动布局-CSDN博客 在上章我们学习了45.qt quick-qml虚拟软键盘详解(一)_诺谦的博客-CSDN博客46.qt quick-自定义非常好看的qml虚拟软键盘-支持换肤、动态… · 2026/9/24 16:05:52

AI黄瓜病虫害防治机器人 QT 信创完整项目
AI黄瓜病虫害防治机器人 QT 信创完整项目

# AI黄瓜病虫害防治机器人 QT 信创完整项目 ## 项目说明 1. 平台:Qt5.15 / Qt6 兼容(适配银河麒麟、统信UOS信创操作系统) 2. 功能:AI图像识别黄瓜病虫害、机器人运动控制、病害数据库、喷洒作业调度、日志记录、本地模型推理 3. 架构:主窗口+AI推理模块+串口机器人控制+… · 2026/9/24 16:05:46

力扣刷题总结(内容简单,个人记录,有问题请各位大佬评论区指出)
力扣刷题总结(内容简单,个人记录,有问题请各位大佬评论区指出)

1. 二分法简单题给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。示例 1:输入: nums [-1,0,3,5,9,12], target 9 输出: 4… · 2026/9/24 16:05:46

Prisma CLI 集群管理实战:`prisma cluster list` 命令详解与集群注册表机制剖析
Prisma CLI 集群管理实战:`prisma cluster list` 命令详解与集群注册表机制剖析

Prisma CLI 集群管理实战:prisma cluster list 命令详解与集群注册表机制剖析 【免费下载链接】prisma1 💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated] 项目地址: https://gitcode.com/gh_mirr… · 2026/9/24 16:05:40

Basic Computer Games 之 Weekday 的 MiniScript 移植:安装运行指南与格里高利历算法源码解析
Basic Computer Games 之 Weekday 的 MiniScript 移植:安装运行指南与格里高利历算法源码解析

示例工程 【免费下载链接】basic-computer-games An updated version of the classic "Basic Computer Games" book, with well-written examples in a variety of common MEMORY SAFE, SCRIPTING programming languages. See https://coding-horror.github.io/basic… · 2026/9/24 16:05:40

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码