Sinon 匹配器实战:用 `sinon.match.defined` 断言“值已定义“
测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载sinon.match.defined是 Sinon 内置匹配器家族中最基础也最常用的成员之一它用于在 spy、stub、fake 的参数断言中要求被检查的值已定义defined。本文将以 docs/concepts/matchers/api/defined.md 为核心骨架结合仓库内真实测试用例与 src/sinon/assert.js 的底层实现讲解它的语义、边界行为、与null/undefined的区分以及它在withArgs、组合匹配器和sinon.assert体系中的实战用法读完即可在测试中正确、精准地使用该匹配器。匹配器的定位让参数断言更模糊或更精确在深入sinon.match.defined之前先明确匹配器在 Sinon 中的位置。根据 docs/concepts/matchers/index.md 的说明匹配器可以作为参数直接传给spy.calledOnspy.calledWithspy.returned对应的sinon.assert系列断言函数spy.withArgs匹配器的作用是在期望值上既可以更模糊、也可以更精确——比如你想断言某个参数传了东西但不关心具体是什么sinon.match.defined就是为这种场景设计的。完整的匹配器清单any、array、bool、defined、falsy、truthy、string、number等 25 个见 docs/concepts/matchers/api/index.md。sinon.match.defined的核心语义原文档对它的描述只有一句话Requires the value to be defined.要求该值已定义。翻译成代码语义就是只要被检查的值不是null也不是undefined匹配即通过。它是一个非空存在性检查与值的具体类型、大小、真假性无关——字符串、数字、布尔值、对象、函数、Symbol 都可以通过唯独null和undefined会被拒绝。官方文档配套测试接受与拒绝的边界仓库中与本文档一一对应的测试位于 docs/tests/docs/matchers/api/defined.test.js它用sinon.fake()配sinon.assert.calledWithMatch精确划定了通过/失败的边界import tap from tap; import * as sinon from sinon; tap.test(sinon.match.defined, (t) { const fake sinon.fake(); // ✅ 接受字符串 fake(hello); t.doesNotThrow(() { sinon.assert.calledWithMatch(fake, sinon.match.defined); }, should accept string); // ✅ 接受数字 0注意0 虽然 falsy但它是已定义的值 fake(0); t.doesNotThrow(() { sinon.assert.calledWithMatch(fake, sinon.match.defined); }, should accept zero); // ✅ 接受布尔值 false同理false 也是已定义的值 fake(false); t.doesNotThrow(() { sinon.assert.calledWithMatch(fake, sinon.match.defined); }, should accept false); fake.resetHistory(); // ❌ 拒绝 null fake(null); t.throws( () sinon.assert.calledWithMatch(fake, sinon.match.defined), /expected fake to be called with match/, should reject null ); fake.resetHistory(); // ❌ 拒绝 undefined fake(undefined); t.throws( () sinon.assert.calledWithMatch(fake, sinon.match.defined), /expected fake to be called with match/, should reject undefined ); t.end(); });这份测试传达出三个关键结论0和false都能通过——sinon.match.defined只关心存在性不关心真值性truthiness。这是它和sinon.match.truthy的本质区别。null与undefined都被拒绝——在 JavaScript 中null常被用来显式表达空值但匹配器把null和undefined一并视为未定义这符合typeof value ! undefined value ! null的经典判空惯例。失败时抛出异常——使用sinon.assert.calledWithMatch时若断言失败会抛出匹配/expected fake to be called with match/的异常测试用例通过t.throws来验证这一点。与truthy/falsy的对比别把已定义当成为真Sinon 提供了三个容易混淆的存在性匹配器匹配器索引 将它们并列列出实际语义对比如下匹配器通过条件示例sinon.match.defined值不是null且不是undefined0✅、false✅、✅、{}✅、null❌、undefined❌sinon.match.truthy值在布尔上下文中为真且已定义1✅、a✅、{}✅、0❌、false❌、null❌sinon.match.falsy值为假含null、undefined0✅、false✅、✅、null✅、undefined✅可以看出defined的判定粒度最粗只要非空即可而truthy/falsy在非空基础上进一步做布尔值判断。因此断言参数传了东西但我不关心具体值 → 用sinon.match.defined断言参数是有效真值如配置开关、非空字符串 → 用sinon.match.truthy断言参数为空/假 → 用sinon.match.falsy。源码级原理匹配器在断言链中如何工作sinon.match.defined属于sinon.match匹配器体系其底层匹配引擎来自 Sinon 的官方依赖sinonjs/samsam见 package.json 中sinonjs/samsam: ^10.0.2的声明。在 src/sinon/assert.js 中sinon.assert.match展示了期望 → 匹配器 → 测试 → 判定的完整链路match: function match(actual, expectation) { const matcher createMatcher(expectation); if (matcher.test(actual)) { assert.pass(match); } else { const formatted [ expected value to match, expected ${inspect(expectation)}, actual ${inspect(actual)}, ]; failAssertion(this, join(formatted, \n)); } },流程拆解createMatcher(expectation)由 samsam 提供把期望值此处即sinon.match.defined这个匹配器对象包装为带.test(value)方法的匹配器matcher.test(actual)对实际值执行判定——对defined而言内部等价于value ! null typeof value ! undefined通过则assert.pass(match)不通过则调用failAssertion抛出带格式化信息的断言失败。同样的匹配判定机制也被calledWithMatch、calledWith等断言复用因此你在任何断言位置使用sinon.match.defined都能得到一致的行为。失败信息的实际输出在 test/src/assert-test.js 中有一个专门针对match.defined失败消息的测试it(assert.calledWith match.defined exception message, function () { this.obj.doSomething(); assert.equals( this.message(calledWith, this.obj.doSomething, match.defined), expected doSomething to be called with arguments \n ${color.red( defined, )}, ); });它验证了当doSomething被调用时没有传入任何参数即实际参数为undefined断言calledWith(fake, match.defined)失败错误消息会把未命中的defined标记为红色帮助开发者快速定位是哪一项匹配条件没有满足。这也解释了为什么在 docs/tests/docs/matchers/api/defined.test.js 中失败断言的正则匹配的是expected fake to be called with match——这正是calledWithMatch系列断言统一的失败消息格式。实战一用withArgs区分无参调用与带参调用sinon.match.defined最常见的实战价值之一是与spy.withArgs配合让同一个 stub/spy 针对是否传入有效参数走不同的行为分支。例如import * as sinon from sinon; const readFile sinon.stub(); // 只有传入了路径参数的调用才走成功路径 readFile .withArgs(sinon.match.defined) .resolves(file-content); // 没有传参undefined或显式传 null 的调用走默认失败路径 readFile .withArgs(sinon.match.falsy) .rejects(new Error(missing path)); await readFile(/etc/hosts); // 命中第一条返回 file-content await readFile(); // 命中第二条抛出错误 await readFile(null); // 命中第二条抛出错误注意由于null和undefined都归入未定义这种写法天然地把忘了传参和显式传 null统一处理成同一条分支减少了分支判断的重复代码。实战二验证回调/中间件是否真的拿到了数据在断言异步回调收到了结果对象但结果对象内容不重要时defined是最简洁的写法const spy sinon.spy(); function fetchData(callback) { // 模拟异步返回 callback({ status: 200, body: ok }); } fetchData(spy); sinon.assert.calledWith(spy, sinon.match.defined); // ✅ 通过了若回调因错误路径被调用为callback(null)或callback()同一句断言立刻失败从而拦截住回调虽然被调用了但根本没拿到数据的伪成功场景。实战三组合匹配器放大表达能力所有 Sinon 匹配器都实现了and与or方法参见 docs/concepts/matchers/combining-matchers.md所有匹配器都实现了and和or允许将多个匹配器逻辑组合结果是要求两个匹配器都返回trueand或其中之一返回trueor的新匹配器。sinon.match.defined同样可以参与组合import * as sinon from sinon; // 参数既已定义又必须是字符串 const stringDefined sinon.match.defined.and(sinon.match.string); // 参数是 number 类型或者已定义的对象 const numOrObject sinon.match.number.or( sinon.match.defined.and(sinon.match.object), );这类组合在接口参数校验类测试中非常实用先保证存在再收紧类型错误定位时也能通过失败消息明确知道是哪一层条件未满足。使用限制与注意事项不校验类型defined只做存在性检查123、abc、{}都会通过若同时需要类型约束务必与sinon.match.string、sinon.match.number、sinon.match.object等类型匹配器组合组合方式见上文。null被视为未定义如果业务代码用null表示合法空值而非错误那么defined会误伤这类场景此时应改用sinon.match.any或自定义匹配器参见 docs/concepts/matchers/custom-matchers.md。适用于所有断言入口无论是spy.calledWith、spy.calledWithMatch、stub.withArgs还是sinon.assert系列sinon.match.defined的判定语义完全一致因为底层都走同一个 samsam 匹配引擎。配合sinon.fake使用官方测试中使用的是sinon.fake()而非传统 spyfake 同样完整支持匹配器断言相关实现见 src/sinon/fake.js新旧 API 行为一致。小结sinon.match.defined用一句话概括就是只要不是null或undefined就算通过。它以 docs/concepts/matchers/api/defined.md 为规范定义由 docs/tests/docs/matchers/api/defined.test.js 锁定行为边界并在 src/sinon/assert.js 与 samsam 引擎的支撑下贯穿spy/stub/fake/sinon.assert全部断言入口。掌握它你就能写出关注参数存在性、而非具体值的高鲁棒性测试这也是绝大多数参数校验型断言的第一步。赞分享测试开发工具【免费下载链接】sinonTest spies, stubs and mocks for JavaScript.项目地址https://gitcode.com/gh_mirrors/si/sinon点击查看免费下载相关推荐Sinon sinon.match.has(property[, expectation]) 完全指南属性存在性匹配与深层值断言Sinon sinon.match.has property , expectation 完全指南属性存在性匹配与深层值断言 本文围绕 Sinon 匹配器 s测试开发工具sinon.match.func 匹配器指南在 Sinon 中断言函数类型参数sinon.match.func 匹配器指南在 Sinon 中断言函数类型参数 sinon.match.func 是 Sinon 匹配器Matcher体系测试开发工具Enzyme高级匹配器开发自定义断言实现Enzyme高级匹配器开发自定义断言实现 在React组件测试中Enzyme提供了强大的组件渲染和操作能力但默认断言有时无法满足复杂业务场景的验证需求。本测试前端上一篇PostHog 推送订阅注册机制解析/api/push_subscriptions/、push.appIds 远程配置与移动 SDK 端到端协议下一篇Argo CD argocd app remove-source 命令详解多源 Application 的源移除与安全删除创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考