Jestは、JavaScriptのテスティングフレームワークです。
一般的にテスティングフレームワークは、モック機能は別ライブラリとなっていることが多いのですが、Jestには組み込みのモックライブラリが存在しています。もちろん他のモックライブラリを利用することもできますが、Jest本体にあるということでこちらを使うことが多いと思います。
このJestに組み込まれているモックライブラリ周りを整理しておこうと思います。
Jestのモック
Test Doubleの分類として、Dummy、Fake、Mock、Spy、Stubがあります*1が、Jestではこのように細かい分類で提供されておらず、基本的には jest.mock
、 jest.spyOn
を使うことになります。
そのため、Test Doubleのどの分類に該当する場合でも jest.mock
や jest.spyOn
を使ったりします。今回は、ライブラリ時点でTest Double全体の機能提供としてAPIが設計されているため、分類をベースとせず、機能の説明だけをしていきます。関数で説明していますが、インスタンスなども同様です。
関数の戻り値を置き換える
jest.mock
、 jest.spyOn
のどちらでも可能です。
// jest.mock の場合 import { target } from 'targetModule'; jest.mock('targetModule'); (target as jest.Mock).mockReturnValue(1);
// jest.spyOn の場合 import * as targetModule from 'targetModule'; const spy = jest.spyOn(targetModule, 'targetFn').mockReturnValue(1);
関数の呼び出しがされていることを検証する
jest.mock
、 jest.spyOn
のどちらでも可能です。
// jest.mock の場合 import { target } from 'targetModule'; jest.mock('targetModule'); let mockObj = (target as jest.Mock); // mock.calls に呼び出されたときの引数の情報を取得できる // length にすれば呼び出し回数となる expect(mockObj.mock.calls[0]).toEqual(1); // mock.results に呼び出されたときの出力の情報を取得できる // value に戻り値が入る // type に正常終了かどうかなどが入る expect(mockObj.mock.results[0].value).toEqual(2); // expectの場合、呼び出し回数のチェックなどは関数が存在する expect(mockObj).toHaveBeenCalledTimes(1);
// jest.spyOn の場合 import * as targetModule from 'targetModule'; const spy = jest.spyOn(targetModule, 'targetFn'); // mockと同じ expect(spy.mock.calls[0]).toEqual(1); expect(spy.mock.results[0].value).toEqual(2);
テストコード側で注入できる関数の呼び出しチェックをしたい
ここまでと同じように jest.mock
や jest.spyOn
でもある程度できるものの、シンプルに jest.fn
でも達成できます。
const mockFn = jest.fn((a, b) => a + b);
func(mockFn);
expect(mockFn).toHaveBeenCalledTimes(1);
テスト独自の実装におきかえたい
jest.mock
、 jest.spyOn
のどちらの場合にも使えます。
import * as targetModule from 'targetModule'; const spy = jest.spyOn(targetModule, 'targetFn'); spy.mockImplementation((a, b) => a + b);
クラスの一部の関数だけをモック化したい
クラスの一部の関数のみをモックにしたい場合、 prototype
に対して行えば、可能です。
import TargetClass from 'targetClass'; jest.spyOn(TargetClass.prototype, 'targetFn');
モックの呼び出し情報、インスタンス化情報を消す
mockClear
を使います。
jest.mock
、 jest.spyOn
、 jest.fn
どれでも使えます。
mockObj.mockClear(); expect(mockObj.mock.calls.length).toBe(0); expect(mockObj.mock.instances.length).toBe(0);
モックの設定も含めてリセットしたい
mockRest
を使います。
mockClear
で削除される情報に加え、 mockImplementation
や mockReturnValue
による設定もリセットされます。
mockObj.mockReset();
オリジナルの実装に戻す
mockRestore
を使います。
こちらは、jest.spyOn
でのみ利用可能です。
spy.mockRestore();
まとめ
JestのMockは分類ベースでAPIが提供されていないものの、やりたいことに対してであれば比較的シンプルかなと思います。
ただし注意点として、 mockRestore
が使えるのは spyOn
だけなので、この点は非常に大きな違いかなと思います。
また、他のテストケースに影響を与えないために、テストケース終了時などに mockClear
、 mockReset
、 mockRestore
は適切に呼び出す必要がありそうです。
*1:これはxUnit Test Patternsによる定義をもとにしています。