Jasmine 断言匹配器 #

什么是匹配器? #

匹配器(Matcher)是 Jasmine 中用于验证测试结果的函数。每个匹配器实现了一个布尔比较,返回 true 或 false,Jasmine 根据结果判断测试是否通过。

基本语法 #

javascript
expect(实际值).匹配器(期望值);

否定断言 #

使用 .not 进行否定断言:

javascript
expect(实际值).not.匹配器(期望值);

相等匹配器 #

toBe - 严格相等 #

使用 === 比较,检查是否是同一个引用:

javascript
describe('toBe matcher', function() {
  it('should check strict equality', function() {
    const a = 1;
    expect(a).toBe(1);

    const obj = { name: 'John' };
    expect(obj).toBe(obj);
    expect(obj).not.toBe({ name: 'John' });
  });

  it('should check undefined', function() {
    let value;
    expect(value).toBe(undefined);
  });
});

toEqual - 深度相等 #

递归比较对象和数组的内容:

javascript
describe('toEqual matcher', function() {
  it('should compare objects deeply', function() {
    const obj1 = { a: 1, b: { c: 2 } };
    const obj2 = { a: 1, b: { c: 2 } };

    expect(obj1).toEqual(obj2);
    expect(obj1).not.toBe(obj2);
  });

  it('should compare arrays', function() {
    const arr1 = [1, 2, { a: 3 }];
    const arr2 = [1, 2, { a: 3 }];

    expect(arr1).toEqual(arr2);
  });

  it('should compare nested structures', function() {
    const data1 = {
      users: [
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' }
      ],
      total: 2
    };

    const data2 = {
      users: [
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' }
      ],
      total: 2
    };

    expect(data1).toEqual(data2);
  });
});

布尔匹配器 #

toBeTruthy / toBeFalsy #

检查值是否为真值或假值:

javascript
describe('boolean matchers', function() {
  describe('toBeTruthy', function() {
    it('should pass for truthy values', function() {
      expect(true).toBeTruthy();
      expect(1).toBeTruthy();
      expect('hello').toBeTruthy();
      expect({}).toBeTruthy();
      expect([]).toBeTruthy();
    });
  });

  describe('toBeFalsy', function() {
    it('should pass for falsy values', function() {
      expect(false).toBeFalsy();
      expect(0).toBeFalsy();
      expect('').toBeFalsy();
      expect(null).toBeFalsy();
      expect(undefined).toBeFalsy();
      expect(NaN).toBeFalsy();
    });
  });
});

toBeTrue / toBeFalse #

严格检查布尔值:

javascript
describe('strict boolean matchers', function() {
  it('should check for true', function() {
    expect(true).toBeTrue();
    expect(1).not.toBeTrue();
    expect('true').not.toBeTrue();
  });

  it('should check for false', function() {
    expect(false).toBeFalse();
    expect(0).not.toBeFalse();
    expect('').not.toBeFalse();
  });
});

toBeDefined / toBeUndefined #

检查变量是否已定义:

javascript
describe('definition matchers', function() {
  it('should check if defined', function() {
    let value = 1;
    expect(value).toBeDefined();
    expect(null).toBeDefined();
  });

  it('should check if undefined', function() {
    let value;
    expect(value).toBeUndefined();
    expect(undefined).toBeUndefined();
  });
});

describe('toBeNull', function() {
  it('should check for null', function() {
    expect(null).toBeNull();
    expect(undefined).not.toBeNull();
    expect(0).not.toBeNull();
    expect('').not.toBeNull();
  });
});

toBeNaN #

检查是否为 NaN:

javascript
describe('toBeNaN', function() {
  it('should check for NaN', function() {
    expect(NaN).toBeNaN();
    expect(0 / 0).toBeNaN();
    expect(parseInt('abc')).toBeNaN();
    expect(1).not.toBeNaN();
  });
});

数字匹配器 #

toBeGreaterThan / toBeLessThan #

比较数字大小:

javascript
describe('comparison matchers', function() {
  it('should check greater than', function() {
    expect(5).toBeGreaterThan(3);
    expect(5).not.toBeGreaterThan(5);
    expect(5).not.toBeGreaterThan(10);
  });

  it('should check less than', function() {
    expect(3).toBeLessThan(5);
    expect(3).not.toBeLessThan(3);
    expect(5).not.toBeLessThan(3);
  });
});

toBeGreaterThanOrEqual / toBeLessThanOrEqual #

比较数字大小(包含等于):

javascript
describe('comparison with equality', function() {
  it('should check greater than or equal', function() {
    expect(5).toBeGreaterThanOrEqual(3);
    expect(5).toBeGreaterThanOrEqual(5);
    expect(5).not.toBeGreaterThanOrEqual(10);
  });

  it('should check less than or equal', function() {
    expect(3).toBeLessThanOrEqual(5);
    expect(3).toBeLessThanOrEqual(3);
    expect(5).not.toBeLessThanOrEqual(3);
  });
});

toBeCloseTo #

比较浮点数(考虑精度误差):

javascript
describe('toBeCloseTo', function() {
  it('should compare floating point numbers', function() {
    expect(0.1 + 0.2).toBeCloseTo(0.3);
    expect(0.1 + 0.2).not.toBe(0.3);
  });

  it('should accept precision parameter', function() {
    const pi = 3.14159;
    expect(pi).toBeCloseTo(3.14, 2);
    expect(pi).toBeCloseTo(3.1416, 3);
    expect(pi).not.toBeCloseTo(3.14, 3);
  });

  it('should handle precision examples', function() {
    expect(0.12345).toBeCloseTo(0.12, 2);
    expect(0.12345).not.toBeCloseTo(0.12, 3);
  });
});

字符串匹配器 #

toContain #

检查字符串是否包含子串:

javascript
describe('toContain for strings', function() {
  it('should check substring', function() {
    expect('hello world').toContain('world');
    expect('hello world').toContain('hello');
    expect('hello world').not.toContain('goodbye');
  });

  it('should be case sensitive', function() {
    expect('Hello World').toContain('Hello');
    expect('Hello World').not.toContain('hello');
  });
});

toMatch #

使用正则表达式匹配:

javascript
describe('toMatch', function() {
  it('should match regex patterns', function() {
    expect('hello world').toMatch(/world/);
    expect('hello world').toMatch(/hello/);
    expect('hello world').not.toMatch(/goodbye/);
  });

  it('should match email pattern', function() {
    const email = 'test@example.com';
    expect(email).toMatch(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/);
  });

  it('should match phone pattern', function() {
    const phone = '123-456-7890';
    expect(phone).toMatch(/^\d{3}-\d{3}-\d{4}$/);
  });

  it('should use case insensitive flag', function() {
    expect('Hello World').toMatch(/hello/i);
  });
});

toStartWith / toEndWith #

检查字符串开头或结尾:

javascript
describe('string boundaries', function() {
  it('should check string start', function() {
    expect('hello world').toStartWith('hello');
    expect('hello world').not.toStartWith('world');
  });

  it('should check string end', function() {
    expect('hello world').toEndWith('world');
    expect('hello world').not.toEndWith('hello');
  });
});

数组匹配器 #

toContain #

检查数组是否包含元素:

javascript
describe('toContain for arrays', function() {
  it('should check array contains element', function() {
    expect([1, 2, 3]).toContain(2);
    expect([1, 2, 3]).not.toContain(4);
  });

  it('should check array contains object', function() {
    const obj = { id: 1 };
    expect([obj, { id: 2 }]).toContain(obj);
    expect([{ id: 1 }, { id: 2 }]).not.toContain({ id: 1 });
  });

  it('should work with strings in array', function() {
    expect(['apple', 'banana', 'orange']).toContain('banana');
  });
});

toHaveSize #

检查数组长度:

javascript
describe('toHaveSize', function() {
  it('should check array length', function() {
    expect([1, 2, 3]).toHaveSize(3);
    expect([]).toHaveSize(0);
  });

  it('should check string length', function() {
    expect('hello').toHaveSize(5);
  });

  it('should check Set/Map size', function() {
    expect(new Set([1, 2, 3])).toHaveSize(3);
    expect(new Map([['a', 1], ['b', 2]])).toHaveSize(2);
  });
});

toBeEmpty #

检查是否为空:

javascript
describe('toBeEmpty', function() {
  it('should check empty array', function() {
    expect([]).toBeEmpty();
    expect([1]).not.toBeEmpty();
  });

  it('should check empty string', function() {
    expect('').toBeEmpty();
    expect('hello').not.toBeEmpty();
  });

  it('should check empty object', function() {
    expect({}).toBeEmpty();
    expect({ a: 1 }).not.toBeEmpty();
  });
});

对象匹配器 #

toHaveProperty #

检查对象是否有某个属性:

javascript
describe('toHaveProperty', function() {
  const user = {
    id: 1,
    name: 'John',
    address: {
      city: 'New York',
      country: 'USA'
    }
  };

  it('should check property exists', function() {
    expect(user).toHaveProperty('name');
    expect(user).toHaveProperty('id');
    expect(user).not.toHaveProperty('age');
  });

  it('should check nested property', function() {
    expect(user).toHaveProperty('address.city');
    expect(user).toHaveProperty('address.country');
  });

  it('should check property value', function() {
    expect(user).toHaveProperty('name', 'John');
    expect(user).toHaveProperty('address.city', 'New York');
  });
});

toBeInstanceOf #

检查对象是否是某个类的实例:

javascript
describe('toBeInstanceOf', function() {
  it('should check instance type', function() {
    class User {}
    const user = new User();

    expect(user).toBeInstanceOf(User);
    expect(user).toBeInstanceOf(Object);
    expect({}).toBeInstanceOf(Object);
    expect([]).toBeInstanceOf(Array);
  });

  it('should check built-in types', function() {
    expect(new Date()).toBeInstanceOf(Date);
    expect(new Error()).toBeInstanceOf(Error);
    expect(new Map()).toBeInstanceOf(Map);
    expect(new Set()).toBeInstanceOf(Set);
  });
});

函数匹配器 #

toThrow #

检查函数是否抛出错误:

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

  function divide(a, b) {
    if (b === 0) {
      throw new Error('Division by zero');
    }
    return a / b;
  }

  it('should check if function throws', function() {
    expect(throwError).toThrow();
    expect(function() {}).not.toThrow();
  });

  it('should check specific error message', function() {
    expect(throwError).toThrowError('Something went wrong');
    expect(function() { divide(1, 0); }).toThrowError('Division by zero');
  });

  it('should check error type', function() {
    expect(throwError).toThrowError(Error);
    expect(function() {
      throw new TypeError('Type error');
    }).toThrowError(TypeError);
  });

  it('should check error with regex', function() {
    expect(throwError).toThrowError(/wrong/);
    expect(function() { divide(1, 0); }).toThrowError(/zero$/);
  });
});

toHaveBeenCalled #

检查 Spy 是否被调用(需要配合 Spy 使用):

javascript
describe('toHaveBeenCalled', function() {
  let spy;

  beforeEach(function() {
    spy = jasmine.createSpy('spy');
  });

  it('should check if spy was called', function() {
    spy();
    expect(spy).toHaveBeenCalled();
  });

  it('should check call count', function() {
    spy();
    spy();
    expect(spy).toHaveBeenCalledTimes(2);
  });

  it('should check call arguments', function() {
    spy('arg1', 'arg2');
    expect(spy).toHaveBeenCalledWith('arg1', 'arg2');
  });
});

异步匹配器 #

toBeResolved / toBeRejected #

检查 Promise 状态:

javascript
describe('async matchers', function() {
  it('should check resolved promise', async function() {
    await expectAsync(Promise.resolve('success')).toBeResolved();
  });

  it('should check rejected promise', async function() {
    await expectAsync(Promise.reject(new Error('failed'))).toBeRejected();
  });

  it('should check resolved value', async function() {
    await expectAsync(Promise.resolve(42)).toBeResolvedTo(42);
  });

  it('should check rejected error', async function() {
    await expectAsync(Promise.reject(new Error('failed')))
      .toBeRejectedWithError(Error, 'failed');
  });
});

类型检查匹配器 #

toBeOfType #

检查值的类型:

javascript
describe('type checking', function() {
  it('should check types', function() {
    expect('hello').toBeOfType('string');
    expect(42).toBeOfType('number');
    expect(true).toBeOfType('boolean');
    expect({}).toBeOfType('object');
    expect([]).toBeOfType('object');
    expect(null).toBeOfType('object');
    expect(undefined).toBeOfType('undefined');
    expect(function() {}).toBeOfType('function');
  });
});

自定义匹配器 #

创建自定义匹配器 #

javascript
describe('custom matchers', function() {
  beforeEach(function() {
    jasmine.addMatchers({
      toBeEven: function() {
        return {
          compare: function(actual) {
            const result = {};
            result.pass = actual % 2 === 0;
            if (result.pass) {
              result.message = `Expected ${actual} not to be even`;
            } else {
              result.message = `Expected ${actual} to be even`;
            }
            return result;
          }
        };
      },

      toBeWithinRange: function() {
        return {
          compare: function(actual, min, max) {
            const result = {};
            result.pass = actual >= min && actual <= max;
            if (result.pass) {
              result.message = `Expected ${actual} not to be within ${min} and ${max}`;
            } else {
              result.message = `Expected ${actual} to be within ${min} and ${max}`;
            }
            return result;
          }
        };
      }
    });
  });

  it('should use custom matcher', function() {
    expect(4).toBeEven();
    expect(3).not.toBeEven();
    expect(5).toBeWithinRange(1, 10);
    expect(15).not.toBeWithinRange(1, 10);
  });
});

全局自定义匹配器 #

javascript
// spec/support/jasmine.json 或 helpers 文件中
beforeEach(function() {
  jasmine.addMatchers({
    toBeValidEmail: function() {
      return {
        compare: function(actual) {
          const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
          return {
            pass: emailRegex.test(actual),
            message: `Expected "${actual}" ${emailRegex.test(actual) ? 'not' : ''} to be a valid email`
          };
        }
      };
    }
  });
});

// 使用
describe('email validation', function() {
  it('should validate email', function() {
    expect('test@example.com').toBeValidEmail();
    expect('invalid-email').not.toBeValidEmail();
  });
});

匹配器对照表 #

匹配器 用途 示例
toBe 严格相等 expect(a).toBe(b)
toEqual 深度相等 expect(obj).toEqual({a:1})
toBeTruthy 真值检查 expect(val).toBeTruthy()
toBeFalsy 假值检查 expect(val).toBeFalsy()
toBeNull null 检查 expect(val).toBeNull()
toBeUndefined undefined 检查 expect(val).toBeUndefined()
toBeDefined 已定义检查 expect(val).toBeDefined()
toBeNaN NaN 检查 expect(val).toBeNaN()
toBeGreaterThan 大于 expect(5).toBeGreaterThan(3)
toBeLessThan 小于 expect(3).toBeLessThan(5)
toBeCloseTo 浮点数近似 expect(0.3).toBeCloseTo(0.3)
toContain 包含 expect(arr).toContain(1)
toMatch 正则匹配 expect(str).toMatch(/pattern/)
toThrow 抛出错误 expect(fn).toThrow()
toHaveBeenCalled Spy 被调用 expect(spy).toHaveBeenCalled()
toBeInstanceOf 实例检查 expect(obj).toBeInstanceOf(Class)
toHaveProperty 属性检查 expect(obj).toHaveProperty(‘name’)

下一步 #

现在你已经掌握了 Jasmine 的各种断言匹配器,接下来学习 测试生命周期 了解测试的执行流程和钩子函数!

最后更新:2026-03-28