Expect 断言
在写测试的时候,我们经常需要检查值是否满足指定的条件。 expect gives you access to a number of "matchers" that let you validate different things.
For additional Jest matchers maintained by the Jest Community check out jest-extended.
The TypeScript examples from this page will only work as documented if you explicitly import Jest APIs:
import {expect, jest, test} from '@jest/globals';
Consult the Getting Started guide for details on how to setup Jest with TypeScript.
参考
- Expect 断言
- Modifiers
- Matchers
.toBe(value).toHaveBeenCalled().toHaveBeenCalledTimes(number).toHaveBeenCalledWith(arg1, arg2, ...).toHaveBeenLastCalledWith(arg1, arg2, ...).toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....).toHaveReturned().toHaveReturnedTimes(number).toHaveReturnedWith(value).toHaveLastReturnedWith(value).toHaveNthReturnedWith(nthCall, value).toHaveLength(number).toHaveProperty(keyPath, value?).toBeCloseTo(number, numDigits?).toBeDefined().toBeFalsy().toBeGreaterThan(number | bigint).toBeGreaterThanOrEqual(number | bigint).toBeLessThan(number | bigint).toBeLessThanOrEqual(number | bigint).toBeInstanceOf(Class).toBeNull().toBeTruthy().toBeUndefined().toBeNaN().toContain(item).toContainEqual(item).toEqual(value).toMatch(regexp | string).toMatchObject(object).toMatchSnapshot(propertyMatchers?, hint?).toMatchInlineSnapshot(propertyMatchers?, inlineSnapshot).toStrictEqual(value).toThrow(error?).toThrowErrorMatchingSnapshot(hint?).toThrowErrorMatchingInlineSnapshot(inlineSnapshot)
- Asymmetric Matchers
expect.anything()expect.any(constructor)expect.arrayContaining(array)expect.not.arrayContaining(array)expect.closeTo(number, numDigits?)expect.objectContaining(object)expect.not.objectContaining(object)expect.stringContaining(string)expect.not.stringContaining(string)expect.stringMatching(string | regexp)expect.not.stringMatching(string | regexp)
- Assertion Count
- Extend Utilities
Expect 断言
expect(value)
The expect function is used every time you want to test a value. You will rarely call expect by itself. Instead, you will use expect along with a "matcher" function to assert something about a value.
下面是一个很容易理解的例子: Let's say you have a method bestLaCroixFlavor() which is supposed to return the string 'grapefruit'. 下面是如何测试:
test('the best flavor is grapefruit', () => {
expect(bestLaCroixFlavor()).toBe('grapefruit');
});
In this case, toBe is the matcher function. 本篇文档下面的部分提供了很多不同的匹配器函数,了解它们可以帮助你测试更多不同的内容。
The argument to expect should be the value that your code produces, and any argument to the matcher should be the correct value. 如果你将它们混合使用,你的测试仍然可以执行,但是测试失败的错误信息看起来会比较奇怪。
Modifiers
.not
If you know how to test something, .not lets you test its opposite. For example, this code tests that the best La Croix flavor is not coconut:
test('the best flavor is not coconut', () => {
expect(bestLaCroixFlavor()).not.toBe('coconut');
});
.resolves
Use resolves to unwrap the value of a fulfilled promise so any other matcher can be chained. If the promise is rejected the assertion fails.
For example, this code tests that the promise resolves and that the resulting value is 'lemon':
test('resolves to lemon', () => {
// make sure to add a return statement
return expect(Promise.resolve('lemon')).resolves.toBe('lemon');
});
Since you are still testing promises, the test is still asynchronous. Hence, you will need to tell Jest to wait by returning the unwrapped assertion.
Alternatively, you can use async/await in combination with .resolves:
test('resolves to lemon', async () => {
await expect(Promise.resolve('lemon')).resolves.toBe('lemon');
await expect(Promise.resolve('lemon')).resolves.not.toBe('octopus');
});
.rejects
Use .rejects to unwrap the reason of a rejected promise so any other matcher can be chained. If the promise is fulfilled the assertion fails.
For example, this code tests that the promise rejects with reason 'octopus':
test('rejects to octopus', () => {
// make sure to add a return statement
return expect(Promise.reject(new Error('octopus'))).rejects.toThrow(
'octopus',
);
});
Since you are still testing promises, the test is still asynchronous. Hence, you will need to tell Jest to wait by returning the unwrapped assertion.
Alternatively, you can use async/await in combination with .rejects.
test('rejects to octopus', async () => {
await expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus');
});
Matchers
.toBe(value)
Use .toBe to compare primitive values or to check referential identity of object instances. It calls Object.is to compare values, which is even better for testing than === strict equality operator.
For example, this code will validate some properties of the can object:
const can = {
name: 'pamplemousse',
ounces: 12,
};
describe('the can', () => {
test('has 12 ounces', () => {
expect(can.ounces).toBe(12);
});
test('has a sophisticated name', () => {
expect(can.name).toBe('pamplemousse');
});
});
Don't use .toBe with floating-point numbers. For example, due to rounding, in JavaScript 0.2 + 0.1 is not strictly equal to 0.3. If you have floating point numbers, try .toBeCloseTo instead.
Although the .toBe matcher checks referential identity, it reports a deep comparison of values if the assertion fails. If differences between properties do not help you to understand why a test fails, especially if the report is large, then you might move the comparison into the expect function. For example, to assert whether or not elements are the same instance:
- rewrite
expect(received).toBe(expected)asexpect(Object.is(received, expected)).toBe(true) - rewrite
expect(received).not.toBe(expected)asexpect(Object.is(received, expected)).toBe(false)
.toHaveBeenCalled()
Also under the alias: .toBeCalled()
Use .toHaveBeenCalled to ensure that a mock function was called.
For example, let's say you have a drinkAll(drink, flavour) function that takes a drink function and applies it to all available beverages. You might want to check that drink gets called. You can do that with this test suite:
function drinkAll(callback, flavour) {
if (flavour !== 'octopus') {
callback(flavour);
}
}
describe('drinkAll', () => {
test('drinks something lemon-flavoured', () => {
const drink = jest.fn();
drinkAll(drink, 'lemon');
expect(drink).toHaveBeenCalled();
});
test('does not drink something octopus-flavoured', () => {
const drink = jest.fn();
drinkAll(drink, 'octopus');
expect(drink).not.toHaveBeenCalled();
});
});
.toHaveBeenCalledTimes(number)
Also under the alias: .toBeCalledTimes(number)
Use .toHaveBeenCalledTimes to ensure that a mock function got called exact number of times.
For example, let's say you have a drinkEach(drink, Array<flavor>) function that takes a drink function and applies it to array of passed beverages. You might want to check that drink function was called exact number of times. You can do that with this test suite:
test('drinkEach drinks each drink', () => {
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenCalledTimes(2);
});
.toHaveBeenCalledWith(arg1, arg2, ...)
Also under the alias: .toBeCalledWith()
Use .toHaveBeenCalledWith to ensure that a mock function was called with specific arguments. The arguments are checked with the same algorithm that .toEqual uses.
For example, let's say that you can register a beverage with a register function, and applyToAll(f) should apply the function f to all registered beverages. To make sure this works, you could write:
test('registration applies correctly to orange La Croix', () => {
const beverage = new LaCroix('orange');
register(beverage);
const f = jest.fn();
applyToAll(f);
expect(f).toHaveBeenCalledWith(beverage);
});