Chai 中文文档 下载 App

写出你的第一条 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');
//      ↑    ↑  ↑  ↑
//      链式装饰词,可读性,不影响断言结果

这些词不是必须的,但强烈建议保留——读起来就像一句自然语言。完整列表见 语言链总览。

下一步

你已经能写基础断言了。接下来: