Mock Functions
ただ出力をテストするだけでなく、他のコードから間接的に呼び出された関数の振る舞いを見張ることができるので、モック関数は "スパイ"とも呼ばれます。 jest.fn()
関数でモック関数を作成できます。 実装が与えられなければ、モック関数は実行時にundefined
を返します。
メソッド
mockFn.getMockName()
mockFn.mock.calls
mockFn.mock.results
mockFn.mock.instances
mockFn.mockClear()
mockFn.mockReset()
mockFn.mockRestore()
mockFn.mockImplementation(fn)
mockFn.mockImplementationOnce(fn)
mockFn.mockName(value)
mockFn.mockReturnThis()
mockFn.mockReturnValue(value)
mockFn.mockReturnValueOnce(value)
mockFn.mockResolvedValue(value)
mockFn.mockResolvedValueOnce(value)
mockFn.mockRejectedValue(value)
mockFn.mockRejectedValueOnce(value)
jest.MockedFunction
jest.MockedClass
リファレンス
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
プロパティには、スローまたは返された値が含まれています。 value
は type === 'incomplete'
の場合は undefined です。
たとえば、あるモック関数 f
が3回呼ばれた時、'result1'
が返り、エラーが発生し、'result2'
が返った場合、mock.returnValues
配列は次のような値になります。
[
{
type: 'return',
value: 'result1',
},
{
type: 'throw',
value: {
/* Error instance */
},
},
{
type: 'return',
value: 'result2',
},
];
mockFn.mock.instances
new
によりモック関数からインスタンス化されたオブジェクトのインスタンス全ての配列。
例: 2回インスタンス化されたモック関数は次のような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()
mockFn.mock.calls
と mockFn.mock.instances
の配列に格納されている全ての情報をリセットします。
2つのアサーションの間でモックの使用状況をクリーンアップしたいときにしばしば役立ちます。
mockClear
は mockFn.mock.calls
とmockFn.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).
mockReset
は mockFn.mock.calls
とmockFn.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.mockRestore
はjest.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
モック関数がmockImplementationOnceによって定義された実装が全て使い切った時は、 呼び出された場合にjest.fn(() => defaultValue)
または .mockImplementation(() => defaultValue)
によって設定されたデフォルトの実装を実行します。
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)
どのモック関数が参照されているのかを示すために、"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)
モック関数が呼ばれるたびに返す値を受け取ります。
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));
次のように async テスト内で sync 関数をモックするのに便利です。
test('async test', async () => {
const asyncMock = jest.fn().mockResolvedValue(43);
await asyncMock(); // 43
});
mockFn.mockResolvedValueOnce(value)
下記の関数の糖衣関数です。
jest.fn().mockImplementationOnce(() => Promise.resolve(value));
複数の async 呼び出しを異なる値で解決させるのに便利です。
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));
常に reject する async モック関数を作るのに便利です。
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 itself is written in TypeScript.
If you are using Create React App then the TypeScript template has everything you need to start writing tests in TypeScript.
Otherwise, please see our Getting Started guide for to get setup with TypeScript.
You can see an example of using Jest with TypeScript in our GitHub repository.
jest.MockedFunction
jest.MockedFunction
is available in the@types/jest
module from version24.9.0
.
The following examples will assume you have an understanding of how Jest mock functions work with JavaScript.
You can use jest.MockedFunction
to represent a function that has been replaced by a Jest mock.
Example using automatic jest.mock
:
// Assume `add` is imported and used within `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);
});
Example using 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 version24.9.0
.
The following examples will assume you have an understanding of how Jest mock classes work with 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);
});