Jest 断言匹配器 #

什么是匹配器? #

匹配器(Matchers)是 Jest 中用于验证测试结果的方法。Jest 提供了丰富的匹配器,可以满足各种测试场景。

javascript
test('example', () => {
  expect(实际值).匹配器(预期值);
});

基本匹配器 #

toBe - 严格相等 #

使用 Object.is 进行比较,检查严格相等:

javascript
test('toBe examples', () => {
  // 基本类型
  expect(1 + 1).toBe(2);
  expect('hello').toBe('hello');
  expect(true).toBe(true);

  // 对象引用(必须是同一个引用)
  const obj = { a: 1 };
  expect(obj).toBe(obj);
  expect({ a: 1 }).not.toBe({ a: 1 }); // 不同引用
});

toEqual - 深度相等 #

递归比较对象的所有属性:

javascript
test('toEqual examples', () => {
  // 对象比较
  expect({ a: 1 }).toEqual({ a: 1 });
  expect({ a: { b: 2 } }).toEqual({ a: { b: 2 } });

  // 数组比较
  expect([1, 2, 3]).toEqual([1, 2, 3]);
  expect([{ id: 1 }]).toEqual([{ id: 1 }]);

  // 嵌套对象
  const user = {
    name: 'John',
    address: {
      city: 'New York',
      country: 'USA'
    }
  };
  expect(user).toEqual({
    name: 'John',
    address: {
      city: 'New York',
      country: 'USA'
    }
  });
});

toStrictEqual - 严格深度相等 #

toEqual 更严格,检查类型和 undefined:

javascript
test('toStrictEqual examples', () => {
  // 区分 undefined 和缺失属性
  expect({ a: undefined }).not.toStrictEqual({});
  expect({ a: undefined }).toEqual({});

  // 区分稀疏数组
  expect([, , 1]).not.toStrictEqual([undefined, undefined, 1]);
});

布尔值匹配器 #

toBeTruthy / toBeFalsy #

javascript
test('boolean matchers', () => {
  // toBeTruthy - 检查是否为真值
  expect(true).toBeTruthy();
  expect(1).toBeTruthy();
  expect('hello').toBeTruthy();
  expect({}).toBeTruthy();
  expect([]).toBeTruthy();

  // toBeFalsy - 检查是否为假值
  expect(false).toBeFalsy();
  expect(0).toBeFalsy();
  expect('').toBeFalsy();
  expect(null).toBeFalsy();
  expect(undefined).toBeFalsy();
  expect(NaN).toBeFalsy();
});

toBeNull / toBeUndefined / toBeDefined #

javascript
test('null and undefined matchers', () => {
  // toBeNull
  expect(null).toBeNull();
  expect(undefined).not.toBeNull();

  // toBeUndefined
  expect(undefined).toBeUndefined();
  expect(null).not.toBeUndefined();

  // toBeDefined
  expect(null).toBeDefined();
  expect(undefined).not.toBeDefined();
});

数字匹配器 #

相等和不等 #

javascript
test('number equality', () => {
  expect(1 + 1).toBe(2);
  expect(1 + 1).toEqual(2);
  expect(1 + 1).not.toBe(3);
});

大小比较 #

javascript
test('number comparisons', () => {
  const value = 10;

  // 大于
  expect(value).toBeGreaterThan(5);
  expect(value).toBeGreaterThan(9);

  // 大于等于
  expect(value).toBeGreaterThanOrEqual(10);
  expect(value).toBeGreaterThanOrEqual(9);

  // 小于
  expect(value).toBeLessThan(20);
  expect(value).toBeLessThan(11);

  // 小于等于
  expect(value).toBeLessThanOrEqual(10);
  expect(value).toBeLessThanOrEqual(11);
});

浮点数比较 #

javascript
test('floating point numbers', () => {
  // 使用 toBeCloseTo 避免浮点精度问题
  expect(0.1 + 0.2).toBeCloseTo(0.3);
  expect(0.1 + 0.2).not.toBe(0.3); // 浮点精度问题

  // 指定精度
  expect(0.1 + 0.2).toBeCloseTo(0.3, 5); // 5位小数精度
  expect(0.1 + 0.2).toBeCloseTo(0.3, 10); // 10位小数精度
});

字符串匹配器 #

完全匹配 #

javascript
test('string equality', () => {
  expect('hello').toBe('hello');
  expect('hello').toEqual('hello');
});

包含匹配 #

javascript
test('string contains', () => {
  // toContain - 检查是否包含子字符串
  expect('hello world').toContain('world');
  expect('hello world').not.toContain('foo');

  // toContainEqual - 检查数组中是否包含特定对象
  expect([{ a: 1 }, { b: 2 }]).toContainEqual({ a: 1 });
});

正则匹配 #

javascript
test('string regex', () => {
  // toMatch - 正则表达式匹配
  expect('hello world').toMatch(/world/);
  expect('hello world').toMatch(/hello/);
  expect('hello world').toMatch(/^hello/);
  expect('hello world').toMatch(/world$/);
  expect('hello world').toMatch(/\s/);
});

字符串长度 #

javascript
test('string length', () => {
  expect('hello').toHaveLength(5);
  expect('hello world').toHaveLength(11);
});

数组匹配器 #

包含元素 #

javascript
test('array contains', () => {
  const arr = [1, 2, 3, 'a', 'b'];

  // toContain - 检查是否包含元素
  expect(arr).toContain(1);
  expect(arr).toContain('a');
  expect(arr).not.toContain(4);

  // toContainEqual - 检查是否包含匹配的对象
  const users = [
    { id: 1, name: 'John' },
    { id: 2, name: 'Jane' }
  ];
  expect(users).toContainEqual({ id: 1, name: 'John' });
});

数组长度 #

javascript
test('array length', () => {
  expect([1, 2, 3]).toHaveLength(3);
  expect([]).toHaveLength(0);
});

数组元素验证 #

javascript
test('array elements', () => {
  // toHaveLength - 检查长度
  expect([1, 2, 3]).toHaveLength(3);

  // toEqual - 深度比较
  expect([1, 2, 3]).toEqual([1, 2, 3]);

  // arrayContaining - 检查是否包含子集
  expect([1, 2, 3, 4, 5]).toEqual(
    expect.arrayContaining([1, 2, 3])
  );
});

对象匹配器 #

属性匹配 #

javascript
test('object properties', () => {
  const user = {
    name: 'John',
    age: 30,
    email: 'john@example.com'
  };

  // toHaveProperty - 检查属性是否存在
  expect(user).toHaveProperty('name');
  expect(user).toHaveProperty('age');
  expect(user).toHaveProperty('address.city'); // 嵌套属性

  // 检查属性值
  expect(user).toHaveProperty('name', 'John');
  expect(user).toHaveProperty('age', 30);
});

对象匹配 #

javascript
test('object matching', () => {
  const user = {
    name: 'John',
    age: 30,
    email: 'john@example.com'
  };

  // objectContaining - 检查是否包含部分属性
  expect(user).toEqual(
    expect.objectContaining({
      name: 'John',
      age: 30
    })
  );

  // 匹配任意值
  expect(user).toEqual(
    expect.objectContaining({
      name: expect.any(String),
      age: expect.any(Number)
    })
  );
});

键匹配 #

javascript
test('object keys', () => {
  const obj = { a: 1, b: 2, c: 3 };

  // 检查是否有特定数量的键
  expect(Object.keys(obj)).toHaveLength(3);
});

异常匹配器 #

toThrow #

javascript
function throwError() {
  throw new Error('Something went wrong');
}

function throwCustomError() {
  throw new TypeError('Invalid type');
}

test('throwing errors', () => {
  // 检查是否抛出错误
  expect(throwError).toThrow();
  expect(throwError).toThrow(Error);

  // 检查错误消息
  expect(throwError).toThrow('Something went wrong');
  expect(throwError).toThrow(/wrong/);

  // 检查错误类型
  expect(throwCustomError).toThrow(TypeError);
  expect(throwCustomError).toThrow('Invalid type');
});

异步异常 #

javascript
async function asyncError() {
  throw new Error('Async error');
}

test('async errors', async () => {
  // 使用 rejects
  await expect(asyncError()).rejects.toThrow('Async error');
  await expect(asyncError()).rejects.toThrow(Error);

  // 使用 .rejects
  await expect(Promise.reject('error')).rejects.toBe('error');
});

函数匹配器 #

调用验证 #

javascript
test('function calls', () => {
  const mockFn = jest.fn();

  mockFn('hello');
  mockFn('world');

  // 检查是否被调用
  expect(mockFn).toHaveBeenCalled();
  expect(mockFn).toHaveBeenCalledTimes(2);

  // 检查调用参数
  expect(mockFn).toHaveBeenCalledWith('hello');
  expect(mockFn).toHaveBeenLastCalledWith('world');
  expect(mockFn).toHaveBeenNthCalledWith(1, 'hello');
  expect(mockFn).toHaveBeenNthCalledWith(2, 'world');
});

返回值验证 #

javascript
test('return values', () => {
  const mockFn = jest.fn();
  mockFn.mockReturnValue(42);
  mockFn.mockReturnValueOnce(1);

  expect(mockFn()).toBe(1);  // 第一次返回 1
  expect(mockFn()).toBe(42); // 之后返回 42
});

异步匹配器 #

Promise #

javascript
test('promise matchers', async () => {
  // resolves
  await expect(Promise.resolve('success')).resolves.toBe('success');
  await expect(Promise.resolve({ data: 'test' })).resolves.toEqual({ data: 'test' });

  // rejects
  await expect(Promise.reject('error')).rejects.toBe('error');
  await expect(Promise.reject(new Error('fail'))).rejects.toThrow('fail');
});

否定匹配器 #

使用 .not 进行否定断言:

javascript
test('negation', () => {
  expect(1 + 1).not.toBe(3);
  expect('hello').not.toContain('world');
  expect([1, 2, 3]).not.toContain(4);
  expect({ a: 1 }).not.toEqual({ b: 2 });
  expect(null).not.toBeUndefined();
});

类型匹配器 #

any #

javascript
test('expect.any', () => {
  // 匹配任何该类型的值
  expect('hello').toEqual(expect.any(String));
  expect(42).toEqual(expect.any(Number));
  expect(true).toEqual(expect.any(Boolean));
  expect(() => {}).toEqual(expect.any(Function));
  expect({}).toEqual(expect.any(Object));
  expect([]).toEqual(expect.any(Array));
});

anything #

javascript
test('expect.anything', () => {
  // 匹配任何非 null 和 undefined 的值
  expect('hello').toEqual(expect.anything());
  expect(42).toEqual(expect.anything());
  expect(null).not.toEqual(expect.anything());
  expect(undefined).not.toEqual(expect.anything());
});

类型构造函数 #

javascript
test('constructor matching', () => {
  class MyClass {}
  const instance = new MyClass();

  expect(instance).toBeInstanceOf(MyClass);
  expect([]).toBeInstanceOf(Array);
  expect({}).toBeInstanceOf(Object);
  expect(() => {}).toBeInstanceOf(Function);
});

快照匹配器 #

toMatchSnapshot #

javascript
test('snapshot matching', () => {
  const user = {
    name: 'John',
    age: 30,
    email: 'john@example.com'
  };

  expect(user).toMatchSnapshot();
});

内联快照 #

javascript
test('inline snapshot', () => {
  const user = { name: 'John' };
  expect(user).toMatchInlineSnapshot(`
    {
      "name": "John"
    }
  `);
});

高级匹配器 #

扩展匹配器 #

javascript
// jest.setup.js
expect.extend({
  toBeWithinRange(received, floor, ceiling) {
    const pass = received >= floor && received <= ceiling;
    if (pass) {
      return {
        message: () => `expected ${received} not to be within range ${floor} - ${ceiling}`,
        pass: true,
      };
    } else {
      return {
        message: () => `expected ${received} to be within range ${floor} - ${ceiling}`,
        pass: false,
      };
    }
  },
});

// 使用自定义匹配器
test('custom matcher', () => {
  expect(5).toBeWithinRange(1, 10);
  expect(15).not.toBeWithinRange(1, 10);
});

数量匹配 #

javascript
test('length assertions', () => {
  // 字符串长度
  expect('hello').toHaveLength(5);

  // 数组长度
  expect([1, 2, 3]).toHaveLength(3);

  // 对象键数量
  expect(Object.keys({ a: 1, b: 2 })).toHaveLength(2);
});

匹配器对照表 #

匹配器 描述
toBe 严格相等(引用相等)
toEqual 深度相等
toStrictEqual 严格深度相等
toBeTruthy 真值
toBeFalsy 假值
toBeNull null
toBeUndefined undefined
toBeDefined 已定义
toBeGreaterThan 大于
toBeGreaterThanOrEqual 大于等于
toBeLessThan 小于
toBeLessThanOrEqual 小于等于
toBeCloseTo 浮点数近似
toMatch 正则匹配
toContain 包含元素
toContainEqual 包含相等对象
toHaveProperty 有属性
toThrow 抛出错误
toHaveBeenCalled 被调用
toHaveBeenCalledTimes 被调用次数
toHaveBeenCalledWith 被调用参数
resolves Promise 成功
rejects Promise 失败
toMatchSnapshot 快照匹配
toBeInstanceOf 实例类型

最佳实践 #

选择合适的匹配器 #

javascript
// ✅ 好的做法
expect(obj).toEqual({ a: 1 });  // 对象比较
expect(arr).toContain(1);       // 数组包含
expect(str).toMatch(/hello/);   // 字符串匹配

// ❌ 不好的做法
expect(JSON.stringify(obj)).toBe(JSON.stringify({ a: 1 }));
expect(arr.indexOf(1) > -1).toBe(true);
expect(str.includes('hello')).toBe(true);

使用语义化断言 #

javascript
// ✅ 好的做法
expect(user).toBeDefined();
expect(items).toHaveLength(3);
expect(error).toThrow();

// ❌ 不好的做法
expect(user !== undefined).toBe(true);
expect(items.length === 3).toBe(true);
expect(() => { throw error }).toThrow();

下一步 #

现在你已经掌握了 Jest 的各种断言匹配器,接下来学习 测试生命周期 了解测试的设置和清理!

最后更新:2026-03-28