Моковые функции
Моковые функции также известны как "шпионы", потому что они позволяют вам следить за поведением функции, которая вызывается косвенно каким-то другим кодом, а не только тестировать результат. Вы можете создать моковую функцию с помощью jest.fn(). Если реализация не задана, моковая функция вернёт undefined при вызове.
Примеры на TypeScript с этой страницы будут работать только в соответствии с документацией, если вы импортируете jest из '@jest/globals'.
import {jest} from '@jest/globals';
Методы
-
Ссылка
mockFn.getMockName()mockFn.mock.callsmockFn.mock.resultsmockFn.mock.instancesmockFn.mock.contextsmockFn.mock.lastCallmockFn.mockClear()mockFn.mockReset()mockFn.mockRestore()mockFn.mockImplementation(fn)mockFn.mockImplementationOnce(fn)mockFn.mockName(name)mockFn.mockReturnThis()mockFn.mockReturnValue(value)mockFn.mockReturnValueOnce(value)mockFn.mockResolvedValue(value)mockFn.mockResolvedValueOnce(value)mockFn.mockRejectedValue(value)mockFn.mockRejectedValueOnce(value)
- Использование TypeScript
Ссылка
mockFn.getMockName()
Возвращает строку имени мока, установленную при вызове mockFn.mockName(value).
mockFn.mock.calls
Массив, содержащий аргументы вызова всех вызовов этой моковой функции. Каждый элемент массива — массив аргументов, переданных во время вызова.
Например: Моковая функция f, которая была вызвана дважды, с аргументами f('arg1', 'arg2'), а затем с аргументами f('arg3', 'arg4'), имела бы массив mock.calls, который выглядит так:
[ ['arg1', 'arg2'], ['arg3', 'arg4'], ];
mockFn.mock.results
Массив, содержащий результаты всех вызовов этой моковой функции. Каждый элемент в этом массиве — объект, содержащий свойство type, и свойство value. type может быть одним из следующих:
-
'return'— Указывает, что вызов завершился обычным возвращением. -
'throw'— Указывает, что вызов завершился сбросом значения. -
'incomplete'— Указывает, что вызов ещё не завершён. Это происходит, если вы тестируете результат внутри самой моковой функции или внутри функции, вызванной моковой функцией.
Свойство value содержит значение, которое было сброшено или возвращено. value является неопределённым, когда type === 'incomplete'.
Например: Моковая функция f, которая была вызвана три раза, возвращала 'result1', выбрасывала ошибку и затем возвращала 'result2', имела бы массив mock.results, который выглядит так:
[
{
type: 'return',
value: 'result1',
},
{
type: 'throw',
value: {
/* Error instance */
},
},
{
type: 'return',
value: 'result2',
},
];
mockFn.mock.instances
Массив, содержащий все экземпляры объектов, которые были созданы из этой моковой функции с помощью new.
Например: Моковая функция, которая была создана дважды, имела бы следующий массив mock.instances:
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
Массив, содержащий контексты всех вызовов моковой функции.
Контекст — это значение this, которое функция получает при вызове. Контекст может быть установлен с помощью Function.prototype.bind, Function.prototype.call или Function.prototype.apply.
Например:
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.
Например: Моковая функция f, которая была вызвана дважды, с аргументами f('arg1', 'arg2'), и затем с аргументами f('arg3', 'arg4'), имела бы массив mock.lastCall, который выглядит так:
['arg3', 'arg4'];
mockFn.mockClear()
Очищает всю информацию, хранящуюся в массивах mockFn.mock.calls, mockFn.mock.instances, mockFn.mock.contexts и mockFn.mock.results. Это часто полезно, когда вам нужно очистить данные о использовании мока между двумя утверждениями.
Обратите внимание, что mockFn.mockClear() заменит mockFn.mock, а не просто сбросит значения его свойств! Поэтому следует избегать присваивания mockFn.mock другим переменным, временным или нет, чтобы убедиться, что вы не обращаетесь к устаревшим данным.
Настройка clearMocks доступна для автоматической очистки моков перед каждым тестом.
mockFn.mockReset()
Делает всё, что делает mockFn.mockClear(), а также удаляет любые смоделированные возвращаемые значения или реализации.
Это полезно, когда вам нужно полностью сбросить моковую функцию до её начального состояния. (Обратите внимание, что сброс шпиона приведёт к функции без возвращаемого значения).
Настройка mockReset доступна для автоматического сброса моков перед каждым тестом.
mockFn.mockRestore()
Делает всё, что делает mockFn.mockReset(), а также восстанавливает исходную (несмоделированную) реализацию.
Это полезно, когда вы хотите моделировать функции в определённых тестовых случаях и восстанавливать исходную реализацию в других.
Обратите внимание, что mockFn.mockRestore() работает только тогда, когда мок был создан с jest.spyOn(). Таким образом, вам нужно позаботиться о восстановлении самостоятельно, при ручном присваивании jest.fn().
Настройка restoreMocks доступна для автоматического восстановления моков перед каждым тестом.
mockFn.mockImplementation(fn)
Принимает функцию, которая должна использоваться как реализация мока. Сам мок всё равно будет записывать все вызовы, которые поступают и экземпляры, которые появляются из него — единственное отличие заключается в том, что реализация также будет выполняться, когда мок вызывается.
jest.fn(implementation) — это сокращение для jest.fn().mockImplementation(implementation).
- JavaScript
- TypeScript
const mockFn = jest.fn(scalar => 42 + scalar); mockFn(0); // 42 mockFn(1); // 43 mockFn.mockImplementation(scalar => 36 + scalar); mockFn(2); // 38 mockFn(3); // 39
const mockFn = jest.fn((scalar: number) => 42 + scalar); mockFn(0); // 42 mockFn(1); // 43 mockFn.mockImplementation(scalar => 36 + scalar); mockFn(2); // 38 mockFn(3); // 39
.mockImplementation() также может использоваться для моделирования конструкторов классов:
- JavaScript
- TypeScript
module.exports = class SomeClass {
method(a, b) {}
};
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);
export class SomeClass {
method(a: string, b: string): void {}
}
import {SomeClass} from './SomeClass';
jest.mock('./SomeClass'); // this happens automatically with automocking
const mockMethod = jest.fn<(a: string, b: string) => void>();
SomeClass.mockImplementation(() => {
return {
method: mockMethod,
};
});
const some = new SomeClass();
some.method('a', 'b');
console.log('Calls to method: ', mockMethod.mock.calls);
mockFn.mockImplementationOnce(fn)
Принимает функцию, которая будет использоваться как реализация мока для одного вызова смоделированной функции. Может быть использовано для определения различных результатов для множественных вызовов.
- JavaScript
- TypeScript
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
const mockFn = jest .fn<(cb: (a: null, b: boolean) => void) => void>() .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), если они были вызваны:
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()' для указания, на какую моковую функцию ссылаются.
Например:
const mockFn = jest.fn().mockName('mockedFunction');
// mockFn();
expect(mockFn).toHaveBeenCalled();
Результат приведет к следующей ошибке:
expect(mockedFunction).toHaveBeenCalled() Expected mock function "mockedFunction" to have been called, but it was not called.
mockFn.mockReturnThis()
Функция синтаксического сахара для:
jest.fn(function () {
return this;
});
mockFn.mockReturnValue(value)
Принимает значение, которое будет возвращаться всякий раз, когда вызывается моковая функция.
- JavaScript
- TypeScript
const mock = jest.fn(); mock.mockReturnValue(42); mock(); // 42 mock.mockReturnValue(43); mock(); // 43
const mock = jest.fn<() => number>(); mock.mockReturnValue(42); mock(); // 42 mock.mockReturnValue(43); mock(); // 43
mockFn.mockReturnValueOnce(value)
Принимает значение, которое будет возвращаться для одного вызова функции-мока. Можно использовать цепочку, чтобы последовательные вызовы функции-мока возвращали разные значения. Когда больше нет mockReturnValueOnce значений, вызовы будут возвращать значение, указанное mockReturnValue.
- JavaScript
- TypeScript
const mockFn = jest
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'
const mockFn = jest
.fn<() => string>()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
mockFn(); // 'first call'
mockFn(); // 'second call'
mockFn(); // 'default'
mockFn(); // 'default'
mockFn.mockResolvedValue(value)
Синтаксический сахар для:
jest.fn().mockImplementation(() => Promise.resolve(value));
Полезно для имитации асинхронных функций в асинхронных тестах:
- JavaScript
- TypeScript
test('async test', async () => {
const asyncMock = jest.fn().mockResolvedValue(43);
await asyncMock(); // 43
});
test('async test', async () => {
const asyncMock = jest.fn<() => Promise<number>>().mockResolvedValue(43);
await asyncMock(); // 43
});
mockFn.mockResolvedValueOnce(value)
Синтаксический сахар для:
jest.fn().mockImplementationOnce(() => Promise.resolve(value));
Полезно для разрешения различных значений при нескольких асинхронных вызовах:
- JavaScript
- TypeScript
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'
});
test('async test', async () => {
const asyncMock = jest
.fn<() => Promise<string>>()
.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)
Синтаксический сахар для:
jest.fn().mockImplementation(() => Promise.reject(value));
Полезно для создания асинхронных функций-моков, которые всегда будут отклонять вызов:
- JavaScript
- TypeScript
test('async test', async () => {
const asyncMock = jest
.fn()
.mockRejectedValue(new Error('Async error message'));
await asyncMock(); // throws 'Async error message'
});
test('async test', async () => {
const asyncMock = jest
.fn<() => Promise<never>>()
.mockRejectedValue(new Error('Async error message'));
await asyncMock(); // throws 'Async error message'
});
mockFn.mockRejectedValueOnce(value)
Синтаксический сахар для:
jest.fn().mockImplementationOnce(() => Promise.reject(value));
Полезно вместе с .mockResolvedValueOnce() или для отклонения с различными исключениями при нескольких асинхронных вызовах:
- JavaScript
- TypeScript
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'
});
test('async test', async () => {
const asyncMock = jest
.fn<() => Promise<string>>()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error message'));
await asyncMock(); // 'first call'
await asyncMock(); // throws 'Async error message'
});
Использование TypeScript
Для получения подробной информации о настройке Jest с TypeScript, обратитесь к руководству Начало работы.
jest.fn(implementation?)
Правильные типы моков будут выведены, если реализация передана в jest.fn(). Существует много случаев, когда реализация опущена. Для обеспечения безопасности типов вы можете передать аргумент обобщенного типа (см. также примеры выше для дополнительной справки):
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).toBeCalledTimes(1);
expect(mockAdd).toBeCalledWith(1, 2);
});
jest.Mocked<Source>
Утилита jest.Mocked<Source> возвращает тип Source, обернутый определениями типов функции-мока Jest.
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>.
jest.mocked(source, options?)
Вспомогательный метод mocked() оборачивает типы объекта source и его глубоко вложенных членов определениями типов функции-мока Jest. Вы можете передать {shallow: true} в качестве аргумента options для отключения глубоко мокированного поведения.
Возвращает объект source.
export const song = {
one: {
more: {
time: (t: number) => {
return t;
},
},
},
};
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);
});
© 2022 Facebook, Inc.
Licensed under the MIT License.
https://jestjs.io/docs/mock-function-api