Open1
Jestでの関数Mock作成について

Jestでの関数Mock作成とメモリ負荷について📝
Jestで特定の関数をモックする代表的な手法をいくつか挙げ、それぞれのメリット・デメリット、サンプルコード、そしてテスト負荷(メモリ使用率など)について整理します。
主なモック手法
-
jest.fn()
での関数モック概要:
jest.fn()
を用いて新規のモック関数を生成します。元の関数実装に依存しないため、最もシンプルな方法です。メリット:
- 簡潔で素早く記述できる
- 任意の戻り値や実行時動作を容易に設定可能(
mockReturnValue
,mockImplementation
など)
デメリット:
- 元のオブジェクトや関数構造を保持しないため、元実装との紐づきを示しにくい
サンプルコード:
const myMockFn = jest.fn(); myMockFn.mockReturnValue('mocked result'); test('myMockFn returns mocked result', () => { expect(myMockFn()).toBe('mocked result'); });
メモリ・テスト負荷:
- 比較的軽量。単純な関数オブジェクトをmockするだけなのでオーバーヘッドは少ない。
-
jest.spyOn()
での既存メソッドモック概要:既存のオブジェクトやクラスのメソッドにスパイを仕掛け、戻り値をモックします。
メリット:
- 元のメソッド構造・オブジェクトを維持しつつ挙動のみ差し替え可能
- テスト後に
mockRestore()
で元状態に戻せる
デメリット:
- 元となるオブジェクトとメソッドが存在することが前提
-
jest.fn()
より多少記述が冗長
サンプルコード:
const obj = { method: () => 'original' }; jest.spyOn(obj, 'method').mockReturnValue('mocked'); test('obj.method returns mocked', () => { expect(obj.method()).toBe('mocked'); });
メモリ・テスト負荷:
- 個別のメソッドに対するスパイなので軽量。
jest.fn()
同様、小規模なら問題なし。
-
jest.mock()
での自動モック(モジュール全体モック)概要:
jest.mock()
を使い、テスト対象のモジュールを丸ごとモックします。__mocks__
ディレクトリを利用することも可能です。メリット:
- モジュール全体を一度にモックできる
- 再利用性が高く、複数テストで同じモックを使用しやすい
デメリット:
- 設定がやや複雑になりやすい
- モジュール単位でモックするため、細かい粒度の制御が難しい
サンプルコード(
__mocks__/myModule.js
を利用する場合):// __mocks__/myModule.js module.exports = { myFunction: jest.fn().mockReturnValue('mocked result') }; // test file jest.mock('../myModule'); // 上記の__mocks__が利用される const { myFunction } = require('../myModule'); test('myFunction returns mocked result', () => { expect(myFunction()).toBe('mocked result'); });
メモリ・テスト負荷:
- モジュール全体を読み込み・モックするため、関数単位のモックよりは若干負荷が上がる可能性あり。ただし一般的な規模のプロジェクトでは大きな問題となりにくい。
-
jest.requireActual()
を用いた部分的モック概要:元のモジュールを
jest.requireActual()
で取得した上で、一部関数のみをモックする手法です。メリット:
- 元のモジュール実装の一部は使用しつつ、一部のみ差し替え可能
- 実用的な「部分モック」が実現しやすい
デメリット:
- 設定がやや複雑
- 部分的な差し替えのため、意図せぬ依存があるとテストが難解になる可能性
サンプルコード:
jest.mock('../myModule', () => { const actualModule = jest.requireActual('../myModule'); return { ...actualModule, myFunction: jest.fn().mockReturnValue('mocked') }; }); const { myFunction, otherFunction } = require('../myModule'); test('myFunction returns mocked', () => { expect(myFunction()).toBe('mocked'); });
メモリ・テスト負荷:
- 実際のモジュールを一度読み込んだ上でモックするため、単純な
jest.fn()
やjest.spyOn()
よりは負荷が上がる場合がある。しかし、大半のケースで問題ない範囲。
メモリ使用率やテスト負荷についてのコメント
- 基本的な関数モック(
jest.fn()
,jest.spyOn()
)は非常に軽量で、テストケースが数十~数百程度ではメモリ負荷や実行時間への影響は僅少です。 -
jest.mock()
で大規模なモジュールをモックする場合、すべての依存関係やモジュールを読み込むため、多少メモリ使用率が上がる可能性があります。ただし、通常のユニットテスト規模では問題になりにくく、テストランナー(Jest)自体が大規模プロジェクトにも対応できるようになっています。 - 大量にモックを乱用すると、テストセットアップのコード量や複雑性が増し、テスト時間が若干延びる場合もありますが、一般的な用途では依然として軽量といえます。
比較表
手法 | 容易度 | 柔軟性 | 元実装への依存 | 適用範囲 | メモリ/CPU負荷 | サンプルコード例 |
---|---|---|---|---|---|---|
jest.fn() |
高(簡単) | 高 (独立関数を自由にモック) | 不要 | 関数単位 | 低(軽量) | const mockFn = jest.fn(); mockFn.mockReturnValue('foo'); |
jest.spyOn() |
中(やや複雑) | 中 (既存メソッドのみ) | 必要 | オブジェクトメソッド | 低(軽量) | jest.spyOn(obj, 'method').mockReturnValue('bar'); |
jest.mock() (自動モック) |
中(普通) | 高 (モジュール全体をモック) | 不要 | モジュール単位 | 中(やや負荷) | jest.mock('../module'); const { fn } = require('../module'); fn.mockReturnValue('mocked'); |
jest.requireActual() 併用 |
低(やや面倒) | 高 (部分的モック可能) | 必要 | モジュールの一部 | 中(やや負荷) | jest.mock('../module', () => { const actual = jest.requireActual('../module'); return {...actual, fn: jest.fn()};}); |
上記を参考に、テスト対象やニーズに合わせて適切なモック手法を選択するとよいでしょう。