メインコンテンツへスキップ
Version: 25.x

モック関数

ただ出力をテストするだけでなく、他のコードから間接的に呼び出された関数の振る舞いを見張ることができるので、モック関数は "スパイ"とも呼ばれます。 jest.fn()関数でモック関数を作成できます。 実装が与えられなければ、モック関数は実行時にundefinedを返します。

メソッド#


リファレンス#

mockFn.getMockName()#

mockFn.mockName(value)を呼び出すと、モック名の文字列を返します。

mockFn.mock.calls#

モック関数に行われた全てのコールを含む配列を返します。 配列の個々の要素は、コールに渡された引数の配列です。

例: f('arg1', 'arg2')f('arg3', 'arg4')の形で2回呼ばれるモック関数fは次のようなmock.callsの配列を持ちます:

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

mockFn.mock.results#

モック関数に対して行われたすべての呼び出しの結果を含む配列。 この配列の各要素は、 タイプ プロパティと プロパティを持つオブジェクトです。 type は以下のいずれかになります:

  • 'return' - 正常終了したコールを示します。
  • 'throw' - 値を返して呼び出しが完了したことを示します。
  • 'incomplete' - 呼び出しがまだ完了していないことを示します。 これは、モック関数自体の中から結果をテストする場合や、モック関数によって呼び出された関数内からの結果をテストする場合に発生します。

value プロパティには、スローまたは返された値が含まれています。 valuetype === 'incomplete' の場合は undefined です。

new によりモック関数からインスタンス化されたオブジェクトのインスタンス全ての配列。

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

mockFn.mock.instances#

例: 2回インスタンス化されたモック関数は次のようなmock.instances配列を持ちます:

mockFn.mock.callsmockFn.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.mockClear()#

2つのアサーションの間でモックの使用状況をクリーンアップしたいときにしばしば役立ちます。

Often this is useful when you want to clean up a mocks usage data between two assertions.

mockClearmockFn.mock.callsmockFn.mock.instancesだけでなくmockFn.mock も置き換えることに注意して下さい。 You should, therefore, avoid assigning mockFn.mock to other variables, temporary or not, to make sure you don't access stale data.

テスト間で自動的にモックをクリアするために clearMocksの設定オプションが利用できます。

mockFn.mockReset()#

Does everything that mockFn.mockClear() does, and also removes any mocked return values or implementations.

This is useful when you want to completely reset a mock back to its initial state. (Note that resetting a spy will result in a function with no return value).

mockResetmockFn.mock.callsmockFn.mock.instancesだけでなくmockFn.mock も置き換えることに注意して下さい。 You should, therefore, avoid assigning mockFn.mock to other variables, temporary or not, to make sure you don't access stale data.

mockFn.mockRestore()#

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

あるテストケースでモック関数を利用して他のテストケースでは本物のモジュールに戻したいときに便利です。

mockFn.mockRestorejest.spyOnによって作成されたモックに対してのみ動作することに注意して下さい。 このため手動で jest.fn()を割り当てた場合は自分で復元作業を行わなければならないことに気をつけて下さい。

テスト間で自動的にモックを復元するために restoreMocksの設定オプションが利用できます。

mockFn.mockImplementation(fn)#

モックの実装として使用される関数を受け取ります。 モック自体はそれ自身から出てきたインスタンスと中に与えられた全てのコールをいまだ記録しています - 違いはモックがコールされたときに実装された関数も実行されることです。

注意: jest.fn(implementation)jest.fn().mockImplementation(implementation) の省略形です。

例:

const mockFn = jest.fn().mockImplementation(scalar => 42 + scalar);
// or: jest.fn(scalar => 42 + scalar);
const a = mockFn(0);
const b = mockFn(1);
a === 42; // true
b === 43; // true
mockFn.mock.calls[0][0] === 0; // true
mockFn.mock.calls[1][0] === 1; // true

mockImplementation はクラスのコンストラクタをモックするのにも使用できます。

SomeClass.js
module.exports = class SomeClass {
m(a, b) {}
};
OtherModule.test.js
jest.mock('./SomeClass'); // this happens automatically with automocking
const SomeClass = require('./SomeClass');
const mMock = jest.fn();
SomeClass.mockImplementation(() => {
return {
m: mMock,
};
});
const some = new SomeClass();
some.m('a', 'b');
console.log('Calls to m: ', mMock.mock.calls);

mockFn.mockImplementationOnce(fn)#

モック関数への1回のコールに対する実装として使用される関数を受け取ります。 関数への複数回のコールが異なる結果を返せるよう、チェーンすることができます。

const myMockFn = jest
.fn()
.mockImplementationOnce(cb => cb(null, true))
.mockImplementationOnce(cb => cb(null, false));
myMockFn((err, val) => console.log(val)); // true
myMockFn((err, val) => console.log(val)); // false

どのモック関数が参照されているのかを示すために、"jest.fn()"の代わりにテスト結果で出力される文字列を引数に取ります。

const myMockFn = jest
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());

mockFn.mockName(value)#

例:

例:

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)#

たとえば、あるモック関数 f が3回呼ばれた時、'result1' が返り、エラーが発生し、'result2' が返った場合、mock.returnValues 配列は次のような値になります。

const mock = jest.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43

mockFn.mockReturnValueOnce(value)#

モック関数を1回呼び出したときに返す値を受け取ります。 次のモック関数へのコールが異なる値を返せるようチェーンすることができます。 使用できる mockReturnValueOnceの値が無い場合は、 mockReturnValueで設定された値を返します。

const myMockFn = jest
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());

mockFn.mockResolvedValue(value)#

モック関数が呼ばれるたびに返す値を受け取ります。

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

下記の関数の糖衣関数です。

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

mockFn.mockResolvedValueOnce(value)#

モック関数が呼ばれるたびに返す値を受け取ります。

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

下記の関数の糖衣関数です。

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)#

モック関数が呼ばれるたびに返す値を受け取ります。

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

下記の関数の糖衣関数です。

test('async test', async () => {
const asyncMock = jest.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // throws "Async error"
});

mockFn.mockRejectedValueOnce(value)#

モック関数が呼ばれるたびに返す値を受け取ります。

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

例:

test('async test', async () => {
const asyncMock = jest
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // first call
await asyncMock(); // throws "Async error"
});

TypeScript#

Jest 自体は TypeScript で記述されています。

Create React App を使用している場合、 TypeScript テンプレート には、TypeScript でテストを書き始めるために必要なものがすべて含まれています。

それ以外の場合は、TypeScript でセットアップするための Getting Started ガイドを参照してください。

JestをTypeScriptで使用する例は、 GitHubリポジトリで見ることができます。

jest.MockedFunction#

jest.MockedFunction@types/jest モジュールのバージョン 24.9.0 で利用できます。

以下の例では、 Jest のモック関数が JavaScriptでどのように動作するか を理解していると仮定します。

jest.MockedFunction を使用して、Jest のモックに置き換えられた関数を表すことができます。

自動 jest.mock を使用した例

// `add`がインポートされ、`calculate`内で使用されると仮定します。
import add from './add';
import calculate from './calc';
jest.mock('./add');
// Our mock of `add` is now fully typed
const mockAdd = add as jest.MockedFunction<typeof add>;
test('calculate calls add', () => {
calculate('Add', 1, 2);
expect(mockAdd).toBeCalledTimes(1);
expect(mockAdd).toBeCalledWith(1, 2);
});

jest.fn を使用した例

// Here `add` is imported for its type
import 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() as jest.MockedFunction<typeof add>;
// Note: You can use the `jest.fn` type directly like this if you want:
// const mockAdd = jest.fn<ReturnType<typeof add>, Parameters<typeof add>>();
// `jest.MockedFunction` is a more friendly shortcut.
// Now we can easily set up mock implementations.
// All the `.mock*` API can now give you proper types for `add`.
// https://jestjs.io/docs/en/mock-function-api
// `.mockImplementation` can now 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.MockedClass#

jest.MockedClass is available in the @types/jest module from version 24.9.0.

以下の例では、 Jest のモッククラスが JavaScript でどのように動作するかを理解していると仮定します。

You can use jest.MockedClass to represent a class that has been replaced by a Jest mock.

Converting the ES6 Class automatic mock example would look like this:

import SoundPlayer from '../sound-player';
import SoundPlayerConsumer from '../sound-player-consumer';
jest.mock('../sound-player'); // SoundPlayer is now a mock constructor
const SoundPlayerMock = SoundPlayer as jest.MockedClass<typeof SoundPlayer>;
beforeEach(() => {
// Clear all instances and calls to constructor and all methods:
SoundPlayerMock.mockClear();
});
it('We can check if the consumer called the class constructor', () => {
const soundPlayerConsumer = new SoundPlayerConsumer();
expect(SoundPlayerMock).toHaveBeenCalledTimes(1);
});
it('We can check if the consumer called a method on the class instance', () => {
// Show that mockClear() is working:
expect(SoundPlayerMock).not.toHaveBeenCalled();
const soundPlayerConsumer = new SoundPlayerConsumer();
// Constructor should have been called again:
expect(SoundPlayerMock).toHaveBeenCalledTimes(1);
const coolSoundFileName = 'song.mp3';
soundPlayerConsumer.playSomethingCool();
// mock.instances is available with automatic mocks:
const mockSoundPlayerInstance = SoundPlayerMock.mock.instances[0];
// However, it will not allow access to `.mock` in TypeScript as it
// is returning `SoundPlayer`. Instead, you can check the calls to a
// method like this fully typed:
expect(SoundPlayerMock.prototype.playSoundFile.mock.calls[0][0]).toEqual(
coolSoundFileName,
);
// Equivalent to above check:
expect(SoundPlayerMock.prototype.playSoundFile).toHaveBeenCalledWith(
coolSoundFileName,
);
expect(SoundPlayerMock.prototype.playSoundFile).toHaveBeenCalledTimes(1);
});