Chai 中文文档 下载 App

equal / not.equal / strictEqual 值相等比较 - 严格 vs 非严格 vs 深度

三种相等语义速查

写法JS 对应适用场景
.equal==允许类型转换,不太常用
.strictEqual(默认)===推荐,行为可预测
.deep.equal深度相等对象 / 数组的"值"比较

.equal —— 非严格相等

对应 == 运算符,允许类型转换:

expect(3).to.equal('3');      // 通过(3 == '3' 是 true)
expect(null).to.equal(undefined);  // 通过(null == undefined 是 true)
expect([]).to.equal('');       // 通过([] == '' 是 true)

不推荐日常使用——类型转换的规则复杂且反直觉,容易掩盖 bug。Chai 默认把 .equal 绑定到严格相等是有道理的。

.strictEqual —— 严格相等(默认)

对应 ===,不做任何类型转换:

expect(3).to.strictEqual(3);       // 通过
expect(3).to.strictEqual('3');     // 失败
expect(null).to.strictEqual(null);  // 通过
expect(null).to.strictEqual(undefined);  // 失败

这是 Chai 的默认行为——平时写的 .equal 实际上就是 .strictEqual:

// 这两条等价
expect(3).to.equal(3);
expect(3).to.strictEqual(3);

为什么 Chai 把 .equal 的行为改成了严格相等?因为 Node.js 内置 assert 的 assert.equal 也是 ==,而 assert.strictEqual 是 ===,但日常测试中大家几乎都想做严格比较。Chai 在 v4+ 把默认行为改成 ===,让 .equal 和直觉一致。

.deep.equal —— 深度相等

解决对象 / 数组的"引用 vs 值"问题:

expect({ a: 1 }).to.equal({ a: 1 });          // 失败(不同引用)
expect({ a: 1 }).to.deep.equal({ a: 1 });     // 通过(值相等)

expect([1, 2, 3]).to.equal([1, 2, 3]);        // 失败
expect([1, 2, 3]).to.deep.equal([1, 2, 3]);    // 通过

深度相等的完整规则见 .deep 修饰器。

.not.equal / .not.deep.equal

expect(42).to.not.equal(43);
expect({ a: 1 }).to.not.deep.equal({ a: 2 });

.notStrictEqual / .notDeepEqual

assert 风格中对应的方法名:

assert.notStrictEqual(3, '3');  // 通过(3 !== '3')
assert.notDeepEqual({ a: 1 }, { a: 2 });  // 通过

浮点精度问题

JavaScript 中 0.1 + 0.2 !== 0.3 是经典问题。直接用 .equal 会失败:

expect(0.1 + 0.2).to.equal(0.3);
// AssertionError: expected 0.30000000000000004 to equal 0.3

解决方案:

详见下一页 .closeTo。

assert 风格完整映射

expect / should 写法assert 写法语义
.equal(a, b)assert.strictEqual(a, b)===
.not.equal(a, b)assert.notStrictEqual(a, b)!==
.deep.equal(a, b)assert.deepEqual(a, b)深度
.not.deep.equal(a, b)assert.notDeepEqual(a, b)深度不等
.eql(a, b)assert.deepEqual(a, b).eql 是 .deep.equal 的别名

.eql 是 .deep.equal 的简写:

expect({ a: 1 }).to.eql({ a: 1 });
// 等价于
expect({ a: 1 }).to.deep.equal({ a: 1 });

错误消息对比

严格相等失败:

expect('hello').to.equal('world');
// AssertionError: expected 'hello' to equal 'world'

深度相等失败(对象差异高亮):

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 }
// + expected - actual
// {
//   a: 1,
// -  b: 2
// +  b: 3
// }

实践建议

  1. 绝大多数场景用 .equal(默认 strictEqual)。
  2. 涉及对象/数组/Map/Set 时加 .deep。
  3. 避免 .not.equal,改断言"是什么"。
  4. 不推荐 .equal(非严格)——类型转换太反直觉。

下一步