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-chaisinon-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 同时支持expect与should两种风格,任君挑选:
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 断言 |
|---|---|
| called | spy.should.have.been.called |
| callCount | spy.should.have.callCount(n) |
| calledOnce | spy.should.have.been.calledOnce |
| calledTwice | spy.should.have.been.calledTwice |
| calledThrice | spy.should.have.been.calledThrice |
| calledBefore | spy1.should.have.been.calledBefore(spy2) |
| calledAfter | spy1.should.have.been.calledAfter(spy2) |
| calledWith | spy.should.have.been.calledWith(...args) |
| calledWithExactly | spy.should.have.been.calledWithExactly(...args) |
| calledWithMatch | spy.should.have.been.calledWithMatch(...matchers) |
| calledOn | spy.should.have.been.calledOn(context) |
| calledWithNew | spy.should.have.been.calledWithNew |
| returned | spy.should.have.returned(value) |
| threw | spy.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是无效的,这是新手最容易踩的坑。
更严格的组合断言
calledOnceWith、calledOnceWithExactly这类组合断言,可以同时校验"调用次数 + 参数",一个断言搞定两件事:
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),仅供参考
