Chai 断言
三种断言风格
const chai = require('chai');
// 1. assert 风格(TDD)
const { assert } = chai;
assert.equal(3, 3);
assert.deepEqual({ a: 1 }, { a: 1 });
assert.isNull(null);
assert.include([1, 2, 3], 2);
// 2. expect 风格(BDD,最流行)
const { expect } = chai;
expect(42).to.equal(42);
expect('hello').to.be.a('string');
expect([1, 2, 3]).to.have.lengthOf(3);
// 3. should 风格(BDD,扩展 Object.prototype)
chai.should();
(42).should.equal(42);
'hello'.should.be.a('string');
expect — 链式调用与常用断言
const { expect } = require('chai');
expect(42).to.be.a('number');
expect([]).to.be.an('array');
expect('foo').to.equal('foo'); // 严格 ===
expect([1, 2]).to.deep.equal([1, 2]); // 深度相等
expect({ a: 1, b: 2 }).to.have.property('a', 1);
expect(obj).to.have.all.keys('a', 'b');
expect([1, 2, 3]).to.include(2);
expect([1, 2, 3]).to.have.members([3, 2, 1]); // 不计顺序
expect(7).to.be.above(5);
expect(5).to.be.within(1, 10);
expect('hello123').to.match(/\d+/);
深度相等与嵌套对象
expect({ a: { b: { c: 3 } } }).to.deep.equal({ a: { b: { c: 3 } } });
expect({ a: { b: 1 } }).to.have.nested.property('a.b', 1);
expect({ arr: [1, 2, 3] }).to.have.nested.property('arr[1]', 2);
expect({ a: 1, b: 2, c: 3 }).to.deep.include({ a: 1, b: 2 });
异常断言
expect(() => JSON.parse('invalid')).to.throw(SyntaxError);
expect(() => throw new Error('Not found')).to.throw(/not found/i);
// 异步断言 — chai-as-promised
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
await expect(Promise.reject(new Error('异步错误')))
.to.be.rejectedWith('异步错误');
await expect(asyncFunction())
.to.eventually.have.property('id');
插件
| 插件 | 安装 | 用途 |
|---|---|---|
| chai-as-promised | npm i chai-as-promised | 异步/Promise 断言 |
| sinon-chai | npm i sinon-chai | Sinon spy/stub 断言 |
| chai-http | npm i chai-http | HTTP 请求测试 |
| chai-subset | npm i chai-subset | 对象部分匹配 |
自定义消息与断言
// 自定义失败消息
expect(user.age, '用户年龄应为数字').to.be.a('number');
// 添加自定义断言方法
chai.Assertion.addMethod('validEmail', function () {
const email = this._obj;
this.assert(
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email),
`期望 #{this} 是合法的邮箱地址`,
`期望 #{this} 不是合法的邮箱地址`
);
});
expect('user@example.com').to.be.a.validEmail();