写出你的第一条 Chai 断言 - expect 风格实战示例
准备工作
在你的 Node.js 项目中确保已安装 Chai:
npm install chai
创建一个测试文件 test/first-chai.test.js。虽然 Mocha / Jest 会自动发现 test/ 目录下的文件,当前先用纯 Node.js 脚本验证 Chai 的断言能力。
从 expect 风格开始
expect 风格是最推荐新手使用的,因为它不修改任何原型、在所有环境(包括 IE9)都能正常工作。
// test/first-chai.test.js
const { expect } = require('chai');
示例一:断言字符串类型和值
const greeting = 'Hello, Chai!';
// 断言类型
expect(greeting).to.be.a('string');
// 断言值完全相等
expect(greeting).to.equal('Hello, Chai!');
// 断言包含子串
expect(greeting).to.include('Chai');
// 断言长度
expect(greeting).to.have.lengthOf(12);
运行:
node -e "require('./test/first-chai.test.js')"
这个命令没有输出说明所有断言通过;如果把某个 equal 的期望值改错,Chai 会抛出 AssertionError 并终止进程。
示例二:断言数值
const PI = 3.14159;
// 相等与近似相等(处理浮点精度问题)
expect(0.1 + 0.2).to.be.closeTo(0.3, 0.0001);
// 大于 / 小于
expect(PI).to.be.above(3);
expect(PI).to.be.below(4);
// 区间包含
expect(PI).to.be.within(3, 4);
示例三:断言数组
const fruits = ['apple', 'banana', 'cherry'];
// 类型
expect(fruits).to.be.an('array');
// 长度
expect(fruits).to.have.lengthOf(3);
// 包含某个元素
expect(fruits).to.include('banana');
// 包含多个成员(无序)
expect(fruits).to.have.members(['cherry', 'banana', 'apple']);
// 包含有序成员
expect(fruits).to.have.ordered.members(['apple', 'banana', 'cherry']);
示例四:断言对象
const config = {
name: 'MyApp',
version: '1.0.0',
features: ['auth', 'analytics']
};
// 拥有某个属性
expect(config).to.have.property('name');
// 属性值精确匹配
expect(config).to.have.property('name', 'MyApp');
// 多个属性
expect(config).to.have.all.keys('name', 'version', 'features');
// 深度匹配嵌套对象
expect(config).to.have.deep.property('features.0', 'auth');
// 部分匹配(对象包含)
expect(config).to.deep.include({ name: 'MyApp' });
断言失败时会发生什么
故意写一个肯定失败的断言看看错误信息:
expect('hello').to.equal('world');
控制台会输出:
AssertionError: expected 'hello' to equal 'world'
错误信息自动包含实际值和期望值,这就是 Chai 的核心价值——让失败有足够的信息量帮你定位问题。
再试一个复杂的:
expect({ a: 1, b: 2 }).to.deep.equal({ a: 1, b: 3 });
输出:
AssertionError: expected { a: 1, b: 2 } to deeply equal { a: 1, b: 3 }
加入消息参数
expect(actual, message) 第二个参数是自定义消息,失败时会拼到错误信息前面:
// 未带消息
expect(42).to.equal(43);
// → "AssertionError: expected 42 to equal 43"
// 带消息
expect(42, '答案不对').to.equal(43);
// → "AssertionError: 答案不对: expected 42 to equal 43"
对于用布尔值、数字这类不自带语义的值做断言时,加个消息能省很多排查时间。
链式调用的语法糖
注意链式中出现的 to、be、a、have、is 等词——它们是 Chai 的语言链(Language Chains),不做实际断言,只是让表达更自然:
expect('hello').to.be.a('string');
// ↑ ↑ ↑ ↑
// 链式装饰词,可读性,不影响断言结果
这些词不是必须的,但强烈建议保留——读起来就像一句自然语言。完整列表见 语言链总览。
下一步
你已经能写基础断言了。接下来: