Skip to main content
Version: 29.7

模拟函数

模拟函数也称为 "spies",因为它们可以让你监视由其他代码间接调用的函数的行为,而不仅仅是测试输出。你可以使用 jest.fn() 创建模拟函数。如果没有给出实现,则模拟函数在调用时将返回 undefined

¥Mock functions are also known as "spies", because they let you spy on the behavior of a function that is called indirectly by some other code, rather than only testing the output. You can create a mock function with jest.fn(). If no implementation is given, the mock function will return undefined when invoked.

信息

仅当你显式导入 Jest API 时,此页面中的 TypeScript 示例才会按照文档说明的方式工作:

¥The TypeScript examples from this page will only work as documented if you explicitly import Jest APIs:

import {expect, jest, test} from '@jest/globals';

有关如何使用 TypeScript 设置 Jest 的详细信息,请参阅 入门 指南。

¥Consult the Getting Started guide for details on how to setup Jest with TypeScript.

方法

¥Methods


参考

¥Reference

mockFn.getMockName()

返回通过调用 .mockName() 设置的模拟名称字符串。

¥Returns the mock name string set by calling .mockName().

mockFn.mock.calls

包含对此模拟函数进行的所有调用的调用参数的数组。数组中的每一项都是调用期间传递的参数数组。

¥An array containing the call arguments of all calls that have been made to this mock function. Each item in the array is an array of arguments that were passed during the call.

例如:已使用参数 f('arg1', 'arg2')、然后使用参数 f('arg3', 'arg4') 调用两次的模拟函数 f 将具有如下所示的 mock.calls 数组:

¥For example: A mock function f that has been called twice, with the arguments f('arg1', 'arg2'), and then with the arguments f('arg3', 'arg4'), would have a mock.calls array that looks like this:

[
['arg1', 'arg2'],
['arg3', 'arg4'],
];

mockFn.mock.results

包含对此模拟函数进行的所有调用的结果的数组。该数组中的每个条目都是一个包含 type 属性和 value 属性的对象。type 将是以下之一:

¥An array containing the results of all calls that have been made to this mock function. Each entry in this array is an object containing a type property, and a value property. type will be one of the following:

  • 'return' - 表示调用完成并正常返回。

    ¥'return' - Indicates that the call completed by returning normally.

  • 'throw' - 表明调用通过抛出一个值来完成。

    ¥'throw' - Indicates that the call completed by throwing a value.

  • 'incomplete' - 表示调用尚未完成。如果你从模拟函数本身内部或从模拟调用的函数内部测试结果,就会发生这种情况。

    ¥'incomplete' - Indicates that the call has not yet completed. This occurs if you test the result from within the mock function itself, or from within a function that was called by the mock.

value 属性包含抛出或返回的值。当 type === 'incomplete'value 未定义。

¥The value property contains the value that was thrown or returned. value is undefined when type === 'incomplete'.

例如:一个模拟函数 f 被调用了 3 次,返回 'result1',抛出错误,然后返回 'result2',将有一个如下所示的 mock.results 数组:

¥For example: A mock function f that has been called three times, returning 'result1', throwing an error, and then returning 'result2', would have a mock.results array that looks like this:

[
{
type: 'return',
value: 'result1',
},
{
type: 'throw',
value: {
/* Error instance */
},
},
{
type: 'return',
value: 'result2',
},
];

mockFn.mock.instances

一个数组,包含已使用 new 从该模拟函数实例化的所有对象实例。

¥An array that contains all the object instances that have been instantiated from this mock function using new.

例如:已实例化两次的模拟函数将具有以下 mock.instances 数组:

¥For example: A mock function that has been instantiated twice would have the following mock.instances array:

const mockFn = jest.fn();

const a = new mockFn();
const b = new mockFn();

mockFn.mock.instances[0] === a; // true
mockFn.mock.instances[1] === b; // true

mockFn.mock.contexts

包含模拟函数的所有调用的上下文的数组。

¥An array that contains the contexts for all calls of the mock function.

上下文是函数调用时接收的 this 值。可以使用 Function.prototype.bindFunction.prototype.callFunction.prototype.apply 设置上下文。

¥A context is the this value that a function receives when called. The context can be set using Function.prototype.bind, Function.prototype.call or Function.prototype.apply.

例如:

¥For example:

const mockFn = jest.fn();

const boundMockFn = mockFn.bind(thisContext0);
boundMockFn('a', 'b');
mockFn.call(thisContext1, 'a', 'b');
mockFn.apply(thisContext2, ['a', 'b']);

mockFn.mock.contexts[0] === thisContext0; // true
mockFn.mock.contexts[1] === thisContext1; // true
mockFn.mock.contexts[2] === thisContext2; // true

mockFn.mock.lastCall

包含对此模拟函数进行的最后一次调用的调用参数的数组。如果该函数没有被调用,它将返回 undefined

¥An array containing the call arguments of the last call that was made to this mock function. If the function was not called, it will return undefined.

例如:已使用参数 f('arg1', 'arg2')、然后使用参数 f('arg3', 'arg4') 调用两次的模拟函数 f 将具有如下所示的 mock.lastCall 数组:

¥For example: A mock function f that has been called twice, with the arguments f('arg1', 'arg2'), and then with the arguments f('arg3', 'arg4'), would have a mock.lastCall array that looks like this:

['arg3', 'arg4'];

mockFn.mockClear()

清除 mockFn.mock.callsmockFn.mock.instancesmockFn.mock.contextsmockFn.mock.results 数组中存储的所有信息。当你想要清理两个断言之间的模拟使用数据时,这通常很有用。

¥Clears all information stored in the mockFn.mock.calls, mockFn.mock.instances, mockFn.mock.contexts and mockFn.mock.results arrays. Often this is useful when you want to clean up a mocks usage data between two assertions.

clearMocks 配置选项可用于在每次测试之前自动清除模拟。

¥The clearMocks configuration option is available to clear mocks automatically before each tests.

提醒

请注意,mockFn.mockClear() 将取代 mockFn.mock,而不仅仅是重置其属性值!因此,你应该避免将 mockFn.mock 分配给其他变量(无论是临时的还是非临时的),以确保你不会访问过时的数据。

¥Beware that mockFn.mockClear() will replace mockFn.mock, not just reset the values of its properties! You should, therefore, avoid assigning mockFn.mock to other variables, temporary or not, to make sure you don't access stale data.

mockFn.mockReset()

执行 mockFn.mockClear() 所做的所有操作,并用空函数替换模拟实现,返回 undefined

¥Does everything that mockFn.mockClear() does, and also replaces the mock implementation with an empty function, returning undefined.

resetMocks 配置选项可用于在每次测试之前自动重置模拟。

¥The resetMocks configuration option is available to reset mocks automatically before each test.

mockFn.mockRestore()

完成 mockFn.mockReset() 所做的一切,并恢复原始(非模拟)实现。

¥Does everything that mockFn.mockReset() does, and also restores the original (non-mocked) implementation.

当你想要在某些测试用例中模拟函数并在其他测试用例中恢复原始实现时,这非常有用。

¥This is useful when you want to mock functions in certain test cases and restore the original implementation in others.

restoreMocks 配置选项可用于在每次测试之前自动恢复模拟。

¥The restoreMocks configuration option is available to restore mocks automatically before each test.

信息

mockFn.mockRestore() 仅在使用 jest.spyOn() 创建模拟时才有效。因此,在手动分配 jest.fn() 时,你必须自己负责恢复。

¥mockFn.mockRestore() only works when the mock was created with jest.spyOn(). Thus you have to take care of restoration yourself when manually assigning jest.fn().

mockFn.mockImplementation(fn)

接受应该用作模拟实现的函数。模拟本身仍然会记录所有进入自身的调用和来自自身的实例 - 唯一的区别是,当调用模拟时,实现也会被执行。

¥Accepts a function that should be used as the implementation of the mock. The mock itself will still record all calls that go into and instances that come from itself – the only difference is that the implementation will also be executed when the mock is called.

提示

jest.fn(implementation)jest.fn().mockImplementation(implementation) 的简写。

¥jest.fn(implementation) is a shorthand for jest.fn().mockImplementation(implementation).

const mockFn = jest.fn(scalar => 42 + scalar);

mockFn(0); // 42
mockFn(1); // 43

mockFn.mockImplementation(scalar => 36 + scalar);

mockFn(2); // 38
mockFn(3); // 39

.mockImplementation() 还可以用于模拟类构造函数:

¥.mockImplementation() can also be used to mock class constructors:

SomeClass.js
module.exports = class SomeClass {
method(a, b) {}
};
SomeClass.test.js
const SomeClass = require('./SomeClass');

jest.mock('./SomeClass'); // this happens automatically with automocking

const mockMethod = jest.fn();
SomeClass.mockImplementation(() => {
return {
method: mockMethod,
};
});

const some = new SomeClass();
some.method('a', 'b');

console.log('Calls to method:', mockMethod.mock.calls);

mockFn.mockImplementationOnce(fn)

接受一个函数,该函数将用作模拟函数的一次调用的模拟实现。可以链接起来,以便多个函数调用产生不同的结果。

¥Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results.

const mockFn = jest
.fn()
.mockImplementationOnce(cb => cb(null, true))
.mockImplementationOnce(cb => cb(null, false));

mockFn((err, val) => console.log(val)); // true
mockFn((err, val) => console.log(val)); // false

当模拟函数用完了用 .mockImplementationOnce() 定义的实现时,它将执行用 jest.fn(() => defaultValue).mockImplementation(() => defaultValue) 设置的默认实现(如果它们被调用):

¥When the mocked function runs out of implementations defined with .mockImplementationOnce(), it will execute the default implementation set with jest.fn(() => defaultValue) or .mockImplementation(() => defaultValue) if they were called:

const mockFn = jest
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');

mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'

mockFn.mockName(name)

接受在测试结果输出中使用的字符串来代替 'jest.fn()',以指示正在引用哪个模拟函数。

¥Accepts a string to use in test result output in place of 'jest.fn()' to indicate which mock function is being referenced.

例如:

¥For example:

const mockFn = jest.fn().mockName('mockedFunction');

// mockFn();
expect(mockFn).toHaveBeenCalled();

会导致这个错误:

¥Will result in this error:

expect(mockedFunction).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls: 0

mockFn.mockReturnThis()

简写为:

¥Shorthand for:

jest.fn(function () {
return this;
});

mockFn.mockReturnValue(value)

简写为:

¥Shorthand for:

jest.fn().mockImplementation(() => value);

接受每当调用模拟函数时都会返回的值。

¥Accepts a value that will be returned whenever the mock function is called.

const mock = jest.fn();

mock.mockReturnValue(42);
mock(); // 42

mock.mockReturnValue(43);
mock(); // 43

mockFn.mockReturnValueOnce(value)

简写为:

¥Shorthand for:

jest.fn().mockImplementationOnce(() => value);

接受一次调用模拟函数时返回的值。可以链接起来,以便对模拟函数的连续调用返回不同的值。当没有更多的 mockReturnValueOnce 值可供使用时,调用将返回 mockReturnValue 指定的值。

¥Accepts a value that will be returned for one call to the mock function. Can be chained so that successive calls to the mock function return different values. When there are no more mockReturnValueOnce values to use, calls will return a value specified by mockReturnValue.

const mockFn = jest
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');

mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'

mockFn.mockResolvedValue(value)

简写为:

¥Shorthand for:

jest.fn().mockImplementation(() => Promise.resolve(value));

在异步测试中模拟异步函数很有用:

¥Useful to mock async functions in async tests:

test('async test', async () => {
const asyncMock = jest.fn().mockResolvedValue(43);

await asyncMock(); // 43
});

mockFn.mockResolvedValueOnce(value)

简写为:

¥Shorthand for:

jest.fn().mockImplementationOnce(() => Promise.resolve(value));

对于解决多个异步调用的不同值很有用:

¥Useful to resolve different values over multiple async calls:

test('async test', async () => {
const asyncMock = jest
.fn()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call')
.mockResolvedValueOnce('second call');

await asyncMock(); // 'first call'
await asyncMock(); // 'second call'
await asyncMock(); // 'default'
await asyncMock(); // 'default'
});

mockFn.mockRejectedValue(value)

简写为:

¥Shorthand for:

jest.fn().mockImplementation(() => Promise.reject(value));

对于创建始终拒绝的异步模拟函数很有用:

¥Useful to create async mock functions that will always reject:

test('async test', async () => {
const asyncMock = jest
.fn()
.mockRejectedValue(new Error('Async error message'));

await asyncMock(); // throws 'Async error message'
});

mockFn.mockRejectedValueOnce(value)

简写为:

¥Shorthand for:

jest.fn().mockImplementationOnce(() => Promise.reject(value));

.mockResolvedValueOnce() 一起使用或拒绝多个异步调用的不同异常:

¥Useful together with .mockResolvedValueOnce() or to reject with different exceptions over multiple async calls:

test('async test', async () => {
const asyncMock = jest
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error message'));

await asyncMock(); // 'first call'
await asyncMock(); // throws 'Async error message'
});

mockFn.withImplementation(fn, callback)

接受一个函数,该函数在执行回调时应临时用作模拟的实现。

¥Accepts a function which should be temporarily used as the implementation of the mock while the callback is being executed.

test('test', () => {
const mock = jest.fn(() => 'outside callback');

mock.withImplementation(
() => 'inside callback',
() => {
mock(); // 'inside callback'
},
);

mock(); // 'outside callback'
});

无论回调是否异步(返回 thenable),都可以使用 mockFn.withImplementation。如果回调是异步的,则会返回一个 promise。等待 promise 将等待回调并重置实现。

¥mockFn.withImplementation can be used regardless of whether or not the callback is asynchronous (returns a thenable). If the callback is asynchronous a promise will be returned. Awaiting the promise will await the callback and reset the implementation.

test('async test', async () => {
const mock = jest.fn(() => 'outside callback');

// We await this call since the callback is async
await mock.withImplementation(
() => 'inside callback',
async () => {
mock(); // 'inside callback'
},
);

mock(); // 'outside callback'
});

替换属性

¥Replaced Properties

replacedProperty.replaceValue(value)

更改已替换属性的值。当你想要替换属性然后在特定测试中调整值时,这非常有用。作为替代方案,你可以对同一属性多次调用 jest.replaceProperty()

¥Changes the value of already replaced property. This is useful when you want to replace property and then adjust the value in specific tests. As an alternative, you can call jest.replaceProperty() multiple times on same property.

replacedProperty.restore()

将对象的属性恢复到原始值。

¥Restores object's property to the original value.

请注意,replacedProperty.restore() 仅在属性值替换为 jest.replaceProperty() 时才起作用。

¥Beware that replacedProperty.restore() only works when the property value was replaced with jest.replaceProperty().

restoreMocks 配置选项可用于在每次测试前自动恢复替换的属性。

¥The restoreMocks configuration option is available to restore replaced properties automatically before each test.

TypeScript 用法

¥TypeScript Usage

信息

仅当你显式导入 Jest API 时,此页面中的 TypeScript 示例才会按照文档说明的方式工作:

¥The TypeScript examples from this page will only work as documented if you explicitly import Jest APIs:

import {expect, jest, test} from '@jest/globals';

有关如何使用 TypeScript 设置 Jest 的详细信息,请参阅 入门 指南。

¥Consult the Getting Started guide for details on how to setup Jest with TypeScript.

jest.fn(implementation?)

如果将实现传递给 jest.fn(),将推断出正确的模拟类型。有许多用例省略了实现。为了确保类型安全,你可以传递泛型类型参数(另请参阅上面的示例以获取更多参考):

¥Correct mock typings will be inferred if implementation is passed to jest.fn(). There are many use cases where the implementation is omitted. To ensure type safety you may pass a generic type argument (also see the examples above for more reference):

import {expect, jest, test} from '@jest/globals';
import type add from './add';
import calculate from './calc';

test('calculate calls add', () => {
// Create a new mock that can be used in place of `add`.
const mockAdd = jest.fn<typeof add>();

// `.mockImplementation()` now can infer that `a` and `b` are `number`
// and that the returned value is a `number`.
mockAdd.mockImplementation((a, b) => {
// Yes, this mock is still adding two numbers but imagine this
// was a complex function we are mocking.
return a + b;
});

// `mockAdd` is properly typed and therefore accepted by anything
// requiring `add`.
calculate(mockAdd, 1, 2);

expect(mockAdd).toHaveBeenCalledTimes(1);
expect(mockAdd).toHaveBeenCalledWith(1, 2);
});

jest.Mock<T>

构造模拟函数的类型,例如 jest.fn() 的返回类型。如果你必须定义递归模拟函数,它会很有用:

¥Constructs the type of a mock function, e.g. the return type of jest.fn(). It can be useful if you have to defined a recursive mock function:

import {jest} from '@jest/globals';

const sumRecursively: jest.Mock<(value: number) => number> = jest.fn(value => {
if (value === 0) {
return 0;
} else {
return value + fn(value - 1);
}
});

jest.Mocked<Source>

jest.Mocked<Source> 工具类型返回用 Jest 模拟函数的类型定义封装的 Source 类型。

¥The jest.Mocked<Source> utility type returns the Source type wrapped with type definitions of Jest mock function.

import {expect, jest, test} from '@jest/globals';
import type {fetch} from 'node-fetch';

jest.mock('node-fetch');

let mockedFetch: jest.Mocked<typeof fetch>;

afterEach(() => {
mockedFetch.mockClear();
});

test('makes correct call', () => {
mockedFetch = getMockedFetch();
// ...
});

test('returns correct data', () => {
mockedFetch = getMockedFetch();
// ...
});

类、函数或对象的类型可以作为类型参数传递给 jest.Mocked<Source>。如果你希望限制输入类型,请使用:jest.MockedClass<Source>jest.MockedFunction<Source>jest.MockedObject<Source>

¥Types of classes, functions or objects can be passed as type argument to jest.Mocked<Source>. If you prefer to constrain the input type, use: jest.MockedClass<Source>, jest.MockedFunction<Source> or jest.MockedObject<Source>.

jest.Replaced<Source>

jest.Replaced<Source> 工具类型返回用 Jest 更换属性 的类型定义封装的 Source 类型。

¥The jest.Replaced<Source> utility type returns the Source type wrapped with type definitions of Jest replaced property.

src/utils.ts
export function isLocalhost(): boolean {
return process.env['HOSTNAME'] === 'localhost';
}
src/__tests__/utils.test.ts
import {afterEach, expect, it, jest} from '@jest/globals';
import {isLocalhost} from '../utils';

let replacedEnv: jest.Replaced<typeof process.env> | undefined = undefined;

afterEach(() => {
replacedEnv?.restore();
});

it('isLocalhost should detect localhost environment', () => {
replacedEnv = jest.replaceProperty(process, 'env', {HOSTNAME: 'localhost'});

expect(isLocalhost()).toBe(true);
});

it('isLocalhost should detect non-localhost environment', () => {
replacedEnv = jest.replaceProperty(process, 'env', {HOSTNAME: 'example.com'});

expect(isLocalhost()).toBe(false);
});

jest.mocked(source, options?)

mocked() 辅助方法使用 Jest 模拟函数的类型定义封装 source 对象及其深层嵌套成员的类型。你可以将 {shallow: true} 作为 options 参数传递以禁用深度模拟行为。

¥The mocked() helper method wraps types of the source object and its deep nested members with type definitions of Jest mock function. You can pass {shallow: true} as the options argument to disable the deeply mocked behavior.

返回 source 对象。

¥Returns the source object.

song.ts
export const song = {
one: {
more: {
time: (t: number) => {
return t;
},
},
},
};
song.test.ts
import {expect, jest, test} from '@jest/globals';
import {song} from './song';

jest.mock('./song');
jest.spyOn(console, 'log');

const mockedSong = jest.mocked(song);
// or through `jest.Mocked<Source>`
// const mockedSong = song as jest.Mocked<typeof song>;

test('deep method is typed correctly', () => {
mockedSong.one.more.time.mockReturnValue(12);

expect(mockedSong.one.more.time(10)).toBe(12);
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
});

test('direct usage', () => {
jest.mocked(console.log).mockImplementation(() => {
return;
});

console.log('one more time');

expect(jest.mocked(console.log).mock.calls).toHaveLength(1);
});

jest.Spied<Source>

构造监视类或函数的类型(即 jest.spyOn() 的返回类型)。

¥Constructs the type of a spied class or function (i.e. the return type of jest.spyOn()).

__utils__/setDateNow.ts
import {jest} from '@jest/globals';

export function setDateNow(now: number): jest.Spied<typeof Date.now> {
return jest.spyOn(Date, 'now').mockReturnValue(now);
}
import {afterEach, expect, type jest, test} from '@jest/globals';
import {setDateNow} from './__utils__/setDateNow';

let spiedDateNow: jest.Spied<typeof Date.now> | undefined = undefined;

afterEach(() => {
spiedDateNow?.mockReset();
});

test('renders correctly with a given date', () => {
spiedDateNow = setDateNow(1_482_363_367_071);
// ...

expect(spiedDateNow).toHaveBeenCalledTimes(1);
});

类或函数的类型可以作为类型参数传递给 jest.Spied<Source>。如果你希望限制输入类型,请使用:jest.SpiedClass<Source>jest.SpiedFunction<Source>

¥Types of a class or function can be passed as type argument to jest.Spied<Source>. If you prefer to constrain the input type, use: jest.SpiedClass<Source> or jest.SpiedFunction<Source>.

使用 jest.SpiedGetter<Source>jest.SpiedSetter<Source> 分别创建间谍 getter 或 setter 的类型。

¥Use jest.SpiedGetter<Source> or jest.SpiedSetter<Source> to create the type of a spied getter or setter respectively.