Spec-Zone.ru › Jest

Функции-заглушки

Функции-заглушки также известны как «шпионы», потому что они позволяют вам следить за поведением функции, которая вызывается косвенно другим кодом, а не только тестировать вывод. Вы можете создать функцию-заглушку с помощью jest.fn(). Если реализация не указана, функция-заглушка вернёт undefined при вызове.

info

Примеры на TypeScript с этой страницы будут работать как задокументировано, только если вы импортируете jest из '@jest/globals':

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

Методы

  • Справочник
    • mockFn.getMockName()
    • mockFn.mock.calls
    • mockFn.mock.results
    • mockFn.mock.instances
    • mockFn.mock.contexts
    • mockFn.mock.lastCall
    • mockFn.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
    • jest.fn(implementation?)
    • jest.Mocked<Source>
    • jest.mocked(source, options?)

Справочник

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) {}
};
SomeClass.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);
SomeClass.test.js
export class SomeClass {
  method(a: string, b: string): void {}
}
SomeClass.ts
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);
SomeClass.test.ts

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.

  • 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;
      },
    },
  },
};
song.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);
});
song.test.ts

© 2022 Facebook, Inc.
Licensed under the MIT License.
https://jestjs.io/docs/mock-function-api/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API