Jest测试语法系列之Expect

1,634 阅读4分钟

Jest 实在是很方便,上手简单,几乎零配置。记录一下学习 Jest matchers。附上大部分说明及示例。

普通匹配器 toBe - toBe 使用 Object.is 来测试是否完全相等 .not - 用来测试相反的用例 .toEqual如果你想检查某个对象的值,请改用 toEqual。

toBe 最简单的测试值的方法是看是否精确匹配。

test('two plus two is four', () => { expect(2 + 2).toBe(4); });

toEqual 如果你想检查某个对象的值,请改用 toEqual。

test('object assignment', () => { const data = {one: 1}; data['two'] = 2; expect(data).toEqual({one: 1, two: 2}); });

.not 用来测试相反的用例

test('null', () => { const n = null; expect(n).not.toBeUndefined(); expect(n).not.toBeTruthy(); });

布尔值匹配器 toBeNull 只匹配 null toBeUndefined 只匹配 undefined toBeDefined 与 toBeUndefined 相反 toBeTruthy 匹配任何 if 语句为真 toBeFalsy 匹配任何 if 语句为假

test('null', () => { const n = null; expect(n).toBeNull(); expect(n).toBeDefined(); expect(n).not.toBeUndefined(); expect(n).not.toBeTruthy(); expect(n).toBeFalsy(); });

test('zero', () => { const z = 0; expect(z).not.toBeNull(); expect(z).toBeDefined(); expect(z).not.toBeUndefined(); expect(z).not.toBeTruthy(); expect(z).toBeFalsy(); });

数字匹配器 .toBeGreaterThan() - 大于 .toBeGreaterThanOrEqual() 大于等于 .toBeLessThan() - 小于 .toBeLessThanOrEqual() - 小于等于 .toBeCloseTo() - 浮点数比较

toBeGreaterThan、toBeGreaterThanOrEqual、toBeLessThan、toBeLessThanOrEqual test('two plus two', () => { const value = 2 + 2; expect(value).toBeGreaterThan(3); expect(value).toBeGreaterThanOrEqual(3.5); expect(value).toBeLessThan(5); expect(value).toBeLessThanOrEqual(4.5);

// toBe 和 toEqual 对于数字来说是一样的
 expect(value).toBe(4); 
 expect(value).toEqual(4); 
});

.toBeCloseTo() 对于比较浮点数的相等,应该使用 toBeCloseTo

test('两个浮点数字相加', () => { const value = 0.1 + 0.2; // 0.30000000000000004 expect(value).toBe(0.3); // 这句会报错,因为 js 浮点数有舍入误差 expect(value).toBeCloseTo(0.3); // 这句可以运行 });

字符串匹配器 toMatch - 正则表达式的字符 .toHaveLength(number) - 判断一个有长度的对象的长度

toMatch 正则表达式的字符

test('there is no I in team', () => { expect('team').not.toMatch(/I/); });

test('but there is a "stop" in Christoph', () => { expect('Christoph').toMatch(/stop/); });

.toHaveLength(number) 判断一个有长度的对象的长度

expect([1, 2, 3]).toHaveLength(3); expect('abc').toHaveLength(3); expect('').not.toHaveLength(5); 1 2 3 数组匹配器 .toContain(item) - 判断数组是否包含特定子项 .toContainEqual(item) - 判断数组中是否包含一个特定对象

.toContain 判断数组是否包含特定子项

const shoppingList = [ 'diapers', 'kleenex', 'trash bags', 'paper towels', 'beer', ];

test('购物清单(shopping list)里面有啤酒(beer)', () => { expect(shoppingList).toContain('beer'); });

.toContainEqual(item) 可以判断数组中是否包含一个特定对象,类似 toEqual 与 toContain 的结合

function myBeverages() { return [ {delicious: true, sour: false}, {delicious: false, sour: true} ] } test('is delicious and not sour', () => { const myBeverage = {delicious: true, sour: false}; expect(myBeverages()).toContainEqual(myBeverage); });

对象匹配器 .toMatchObject(object) - 判断一个对象嵌套的 key 下面的 value 类型 .toHaveProperty(keyPath, value) - 判断在指定的 path 下是否有这个属性

.toMatchObject(object) 判断一个对象嵌套的 key 下面的 value 类型,需要传入一个对象。

const houseForSale = { bath: true, bedrooms: 4, kitchen: { amenities: ['oven', 'stove', 'washer'], area: 20, wallColor: 'white', }, }; const desiredHouse = { bath: true, kitchen: { amenities: ['oven', 'stove', 'washer'], wallColor: expect.stringMatching(/white|yellow/), }, };

test('the house has my desired features', () => { expect(houseForSale).toMatchObject(desiredHouse); });

.toHaveProperty(keyPath, value) 判断在指定的 path 下是否有这个属性,嵌套的 path 可以用 '.'分割,也可以用数组。

// Object containing house features to be tested const houseForSale = { bath: true, bedrooms: 4, kitchen: { amenities: ['oven', 'stove', 'washer'], area: 20, wallColor: 'white', }, };

test('this house has my desired features', () => { // Simple Referencing expect(houseForSale).toHaveProperty('bath'); expect(houseForSale).toHaveProperty('bedrooms', 4);

expect(houseForSale).not.toHaveProperty('pool');

// Deep referencing using dot notation expect(houseForSale).toHaveProperty('kitchen.area', 20); expect(houseForSale).toHaveProperty('kitchen.amenities', [ 'oven', 'stove', 'washer', ]);

expect(houseForSale).not.toHaveProperty('kitchen.open');

// Deep referencing using an array containing the keyPath expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20); expect(houseForSale).toHaveProperty( ['kitchen', 'amenities'], ['oven', 'stove', 'washer'], ); expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven');

expect(houseForSale).not.toHaveProperty(['kitchen', 'open']); });

自定义匹配器 使用expect.extend将自己的匹配器添加到Jest。自定义匹配器需要返回一个包含两个key 的对象

{ pass:false //‘布尔值’, message: () => 'message string' //‘函数,该函数返回一个提示信息’ }

expect.extend({ toBeDivisibleBy(received, argument) { const pass = received % argument == 0; if (pass) { return { message: () => expected ${received} not to be divisible by ${argument}, pass: true, }; } else { return { message: () => expected ${received} to be divisible by ${argument}, pass: false, }; } }, });

test('even and odd numbers', () => { expect(100).toBeDivisibleBy(2); expect(101).not.toBeDivisibleBy(2); });

这些帮助函数可以在自定义匹配器中的this中找到:

this.isNot this.equals(a, b) this.utils(matcherHint, printExpected and printReceived)

其他 toThrow - 要测试的特定函数会在调用时抛出一个错误 .resolves 和 .rejects - 用来测试 promise .toHaveBeenCalled() - 用来判断一个函数是否被调用过 .toHaveBeenCalledTimes(number) - 判断函数被调用过几次

toThrow 要测试的特定函数会在调用时抛出一个错误

function compileAndroidCode() { throw new ConfigError('you are using the wrong JDK'); }

test('compiling android goes as expected', () => { expect(compileAndroidCode).toThrow(); expect(compileAndroidCode).toThrow(ConfigError);

// You can also use the exact error message or a regexp expect(compileAndroidCode).toThrow('you are using the wrong JDK'); expect(compileAndroidCode).toThrow(/JDK/); });

.resolves 和 .rejects 用来测试 promise

//resolves test('resolves to lemon', () => { // make sure to add a return statement return expect(Promise.resolve('lemon')).resolves.toBe('lemon'); });

//rejects test('resolves to lemon', async () => { await expect(Promise.resolve('lemon')).resolves.toBe('lemon'); await expect(Promise.resolve('lemon')).resolves.not.toBe('octopus'); });

.toHaveBeenCalled() .toHaveBeenCalled() 也有个别名是.toBeCalled(),用来判断一个函数是否被调用过。

describe('drinkAll', () => { test('drinks something lemon-flavored', () => { const drink = jest.fn(); drinkAll(drink, 'lemon'); expect(drink).toHaveBeenCalled(); });

test('does not drink something octopus-flavored', () => { const drink = jest.fn(); drinkAll(drink, 'octopus'); expect(drink).not.toHaveBeenCalled(); }); });

.toHaveBeenCalledTimes(number) 和 toHaveBeenCalled 类似,判断函数被调用过几次。

test('drinkEach drinks each drink', () => { const drink = jest.fn(); drinkEach(drink, ['lemon', 'octopus']); expect(drink).toHaveBeenCalledTimes(2); });