当前位置: 首页 > news >正文

sinon-chai 是什么?为 Chai 断言库注入 Sinon.JS 能力的完整指南

sinon-chai 是什么?为 Chai 断言库注入 Sinon.JS 能力的完整指南

【免费下载链接】sinon-chaiExtends Chai with assertions for the Sinon.JS mocking framework.项目地址: https://gitcode.com/gh_mirrors/si/sinon-chai

sinon-chai 是什么?它是 Chai 断言库最流行的插件之一,专门为 Sinon.JS 模拟框架设计,把 spy、stub、mock 的全部断言能力转化为原生的expect/should链式语法。本指南将带你快速掌握 sinon-chai 的安装配置、断言速查表、实战用例与进阶技巧,帮助你写出更清晰、更优雅的单元测试代码。

sinon-chai 是什么?为什么单元测试需要它

在 JavaScript 单元测试中,"Mocha + Chai + Sinon.JS" 是经典三件套:

  • Mocha:测试运行框架
  • Chai:断言库,提供expect/should/assert三种风格
  • Sinon.JS:spy、stub、mock 模拟工具

三者各自优秀,但组合使用时有一个尴尬点:Sinon.JS 自带的断言是函数式写法,不够直观:

sinon.assert.calledWith(mySpy, "foo");

而 Chai 的链式语法虽然优美,却不能直接作用于 spy 对象,强行写会非常别扭:

mySpy.calledWith("foo").should.be.ok;

sinon-chai 正是为此而生:它把 Sinon.JS 的所有断言"翻译"成 Chai 风格的链式断言,让测试代码读起来像一句完整的自然语言:

mySpy.should.have.been.calledWith("foo"); expect(mySpy).to.have.been.calledWith("foo");

它的核心实现非常轻量,就是一个标准的 Chai 插件,全部源码集中在 lib/sinon-chai.js 一个文件里,通过chai.use()注册即可生效。

sinon-chai 快速安装:npm 三步配置法

第一步:安装依赖

确保已安装 Node.js 环境,然后执行:

npm install --save-dev sinon-chai

sinon-chai 通过 peerDependencies 要求项目中已有 chai(^5 或 ^6)和 sinon(>=4),所以别忘了:

npm install --save-dev chai sinon

第二步:注册插件

在测试入口文件(或 Mocha 的 setup 文件)中引入并注册:

import * as chai from "chai"; import sinonChai from "sinon-chai"; chai.use(sinonChai);

第三步:选择断言风格

sinon-chai 同时支持expectshould两种风格,任君挑选:

const expect = chai.expect; expect(spy).to.have.been.called; // expect 风格 spy.should.have.been.called; // should 风格

官方测试项目中的公共配置 test/common.js 就是标准的注册范例,可以直接参考。

sinon-chai 断言速查表:从 called 到 threw

sinon-chai 几乎覆盖了 Sinon.JS 的全部常用断言,下面以should风格列出(expect等价写法同样可用):

Sinon.JS 属性/方法sinon-chai 断言
calledspy.should.have.been.called
callCountspy.should.have.callCount(n)
calledOncespy.should.have.been.calledOnce
calledTwicespy.should.have.been.calledTwice
calledThricespy.should.have.been.calledThrice
calledBeforespy1.should.have.been.calledBefore(spy2)
calledAfterspy1.should.have.been.calledAfter(spy2)
calledWithspy.should.have.been.calledWith(...args)
calledWithExactlyspy.should.have.been.calledWithExactly(...args)
calledWithMatchspy.should.have.been.calledWithMatch(...matchers)
calledOnspy.should.have.been.calledOn(context)
calledWithNewspy.should.have.been.calledWithNew
returnedspy.should.have.returned(value)
threwspy.should.have.thrown(error)

这些断言不仅适用于 spy 本身,还可以直接作用于某一次具体调用spy.getCall(0),非常灵活。完整的断言行为定义与边界测试用例,都可以在 test/callArguments.js、test/callCount.js、test/returning.js 等测试文件中找到。

sinon-chai 实战:编写第一个完整用例

以回调函数的测试为例(来自官方 README 的经典场景):

import * as chai from "chai"; import sinon from "sinon"; import sinonChai from "sinon-chai"; chai.should(); chai.use(sinonChai); function hello(name, cb) { cb("hello " + name); } describe("hello", function () { it("应该用正确的问候语调用回调", function () { const cb = sinon.spy(); hello("foo", cb); cb.should.have.been.calledWith("hello foo"); }); });

整个断言读起来就是一句完整的英文句子:"cb 应当已经被调用过,且参数是 hello foo"。相比sinon.assert.calledWith(cb, "hello foo"),可读性提升了不止一个档次,测试失败时的错误信息也来自 Sinon 的格式化输出,定位问题一目了然。

sinon-chai 进阶技巧:.not 取反与 always 断言

用 .not 轻松表达"不应该发生"

任何断言都可以通过 Chai 的.not取反,例如:

spy.should.not.have.been.called; // 从未被调用 spy.should.not.have.been.calledWith("foo"); // 未被用 foo 调用过

用 always 表达"每一次调用都如此"

当 spy 被多次调用时,可以用always前缀要求"每一次调用都满足条件":

spy.should.always.have.been.calledWith("foo"); // ✅ 正确写法

⚠️ 注意:always必须放在have之前,写成should.have.been.alwaysCalledWith是无效的,这是新手最容易踩的坑。

更严格的组合断言

calledOnceWithcalledOnceWithExactly这类组合断言,可以同时校验"调用次数 + 参数",一个断言搞定两件事:

spy.should.always.have.been.calledOnceWithExactly("foo");

sinon-chai 常见问题速查

报错 "is not a spy" 怎么办?

sinon-chai 只能用于 Sinon.JS 创建的 spy、stub、mock 及其调用对象。对普通函数使用会抛出TypeError: xx is not a spy or a call to a spy!,请检查断言对象是否来自sinon.spy()sinon.stub()

calledWith 和 calledWithExactly 有何区别?

  • calledWith:宽松匹配,允许实际调用包含额外参数
  • calledWithExactly:严格匹配,要求参数完全一致

如何校验抛出的错误?

使用thrown断言,可以传入错误对象、错误类型字符串或什么都不传:

spy.should.have.thrown(); spy.should.have.thrown("TypeError"); spy.should.have.thrown(new Error("boom"));

总结

sinon-chai 用极小的体积把 Chai 断言库和 Sinon.JS 模拟框架无缝打通,让 spy、stub、mock 的验证从"函数式调用"进化为"自然语言式断言",同时保留了 Sinon 精确、信息丰富的错误消息。对于使用 Mocha + Chai + Sinon.JS 技术栈的团队来说,它是一个即插即用、收益立竿见影的测试利器,强烈推荐加入你的开发依赖。

如果你想查看完整源码和全部测试用例,可以克隆仓库:https://gitcode.com/gh_mirrors/si/sinon-chai

【免费下载链接】sinon-chaiExtends Chai with assertions for the Sinon.JS mocking framework.项目地址: https://gitcode.com/gh_mirrors/si/sinon-chai

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.cnnetsun.cn/news/4135875.html

相关文章:

  • 10个嵌入式实战场景:用Ring-Buffer解决UART、ADC与日志缓存难题
  • 自编码器实战:从图像去噪到3D卷积,原理与PyTorch实现详解
  • 结构正则表达式入门:用ad的EDIT模式实现强大的批量文本编辑
  • Excel批量隐藏与保护公式:从原理到VBA自动化实战
  • 拖延症自救!亲测这6款AI论文软件,从构思到降重全程逆袭
  • ROS机器人开发入门:Topic与Service通信机制详解与实战
  • 深入解析SQLite B-Tree平衡算法:从原理到工程实现
  • 蓝桥杯国赛模拟题核心解法:事件驱动与状态快照
  • VnCoreNLP性能实测:处理10万条越南语新闻需要多久?与NLP-progress基准全面对比
  • 单片机计算机毕设之基于 STM32 的车载环境参数阈值可调智能控制系统设计 基于 STM32 的 OLED 显示车载雨温传感智能执行系统设计(013404)
  • 用JSONC优化表单提交:3步让POST请求体积大幅下降
  • 前端动画布局与自定义属性实践
  • 构建之后如何运行容器?gradle-docker 的 DockerRun 任务实战(端口映射/环境变量/数据卷)
  • 如何用Kiwix书签打造个人离线知识库?8个实用技巧
  • 训练交付前的检查
  • 基于Docker Compose的云速工具箱开发环境搭建实战指南
  • 投影仪选购避坑指南:聚焦亮度、芯片与系统三大核心
  • 白鲨优化算法(WSO)原理详解与Matlab实现:解决复杂优化问题
  • 如何在10分钟内跑起AMA Protocol本地测试网?保姆级教程
  • 基于拓扑意识场论(TCFT)的碳硅共生体法律主体资格核心标准详析
  • AI短剧制作全流程拆解:从脚本到成片的工程化实践指南
  • 从模型里删掉汽车:Erasing Concepts from Diffusion Models物体擦除实战
  • 基于AI与混合搜索的企业知识库构建:从语义检索到RBAC权限管理
  • Enterprise Commerce 重定向优化:如何用布隆过滤器处理数万条重定向零延迟
  • 2026年Java面试题库与备考策略全解析
  • EmbodiedScan多视角3D检测实战:从零训练你的第一个检测模型(附完整命令)
  • 基于Spring Boot与Vue的论坛数据可视化系统全栈开发实战
  • zigbee_home传感器类型大盘点:12种传感器配置快速参考指南
  • 从零部署本地AI智能体:基于WorkBuddy与Ollama的实战指南
  • 人形机器人退潮,场景化落地成为AI与机器人行业新焦点