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