Javascriptのモジュール形式はESMに移行しつつありますが、テストツールのJestはESMのコードにモックを注入できません。
バンドラーがESMとcommonJSの両形式に対応しているのであれば、差し替えたい関数を含むモジュール(ファイル)のみcommonJSで実装することでモック実装可能です。
モック対象の関数をcommonJSで実装
ESMのexport function some_fn() { ... }
に対応するcommonJSのエクスポートは以下のように記述します。
module.exports = {
some_fn: function () {
return "some meaningful result";
}
}
バンドラーがcommonJSに対応していればこのモジュールは、インポート側でimport { some_fn } from './some_fn.js'
の形式でインポートできます。
テストコード内のモック実装
commonJSでエクスポートしたモジュールであれば、jest.spyOn()
で差し替え可能です。
spyOn()
の第1引数はrequire
したモジュール、第2引数は関数名です。
spyOn()でモックに失敗した場合には、テスト実行時に比較的参考になるエラーが表示されます。
エクスポートしたモジュール構造と一致していない場合が多いでしょう。
const mod = require('./some_fn.js');
const spy = jest.spyOn(mod, 'some_fn').mockImplementation(
() => {
return "mocked result";
});
mockImplementation()
内には、テスト時に実行したいモック関数を実装できます。
モック関数のインスペクション
spyOn()
関数などは実装を差し替えるとともに
モック関数オブジェクトを返します。上の例では、spy
にモック関数を格納しています。
テストケース実行後に、spy.mock.calls
プロパティにはケース内で呼び出された履歴が入っています。
他のテストメトリクスと同様、expect()
で回数や引数をインスペクトできます。
テストケースごとに異なる値を返す例
テスト前のセットアップではspyOn()
で止めておき、各テストケースで実装すると、テストケースごとに異なるモックを利用できます。
以下の例では、ブラウザの言語設定を差し替えています。mockReturnValue()
で実装すると戻り値を定義できます。
let lang;
beforeEach(() => {
lang = jest.spyOn(window.navigator, 'languages', 'get');
});
afterEach(() => {
jest.clearAllMocks();
});
test("English browser", () => {
lang.mockReturnValue(['en-US']);
});
test("Japanese browser", () => {
lang.mockReturnValue(['ja-JP']);
});
Chuma Takahiro