Jestテスト|モック(Mock)を活用したテストコードの書き方

Jestテストにおけるモック(Mock)とは?

5/28/2025

モック(Mock)とは?

実際の関数やAPIなどの「本物の処理の代わりに使うダミー(偽物)」のこと。
Mockを使用すると、下記のようなことができるようになる。

  • 外部APIなどテスト時に呼びたくない処理を回避する
  • 未実装の関数でも先にテストできる
  • 関数の呼び出し状況を検証できる

モックの「作り方」にはいくつかある

🛠 よく使うモックの作り方:

モックの作り方

説明

jest.fn()

自分でゼロからモック関数を作る

jest.spyOn(obj, 'method')

すでにある関数の動きを監視・モック化する

jest.mock('モジュール')

ファイル・モジュール全体をモックに置き換える


jest.fn()

未実装の関数を仮で作ってテストしたいときや、外部の関数の代わりにテスト用の関数を使いたいときに便利。

🔸①テスト対象のモジュール|apiHandler.ts

例として、データ取得後に処理(callback)を呼ぶ関数fetchDataを作成。

export function fetchData(callback: (data: string) => void) {
  // ここは本来、APIからデータ取得処理などがある想定
  // 今は簡単に即時でコールバック呼び出し
  callback('取得したデータ');
}
  • callback は引数で、関数を受け取る形。つまり fetchData に「こういう処理をしてね」という関数を渡すことができる。
  • fetchData の中で、その callback 関数を呼び出すとき、'取得したデータ' という文字列を引数として渡す。

🔸②これを使う関数|dataProcessor.ts

import { fetchData } from './apiHandler';

export function processData() {
  fetchData((result) => {
    console.log('データ処理中:', result);
  });
}
  • ここで fetchData に渡しているのは、匿名関数(無名関数)。(result) => {console.log('データ処理中:', result); }がその関数。
  • この無名関数は 「fetchDataが呼び出すコールバック関数」 になる。
  • result は、このコールバック関数の引数。
  • fetchData関数内で、コールバック関数として呼び出されたこの匿名関数は、引数として'取得したデータ'を渡されている。そのためresult = '取得したデータ'となる。

🔸③テストコード|fetchData.test.ts

  • fetchData が ちゃんとコールバックを呼んでいるか
  • コールバックが 正しい引数で呼ばれているか
import { fetchData } from './apiHandler';

test('fetchDataはコールバックを正しい引数で呼ぶ', () => {
  const mockCallback = jest.fn(); // 空のモック関数を作成

  fetchData(mockCallback); // モック関数をコールバックに渡して実行

  // 関数が1回以上呼ばれたかチェック
  expect(mockCallback).toHaveBeenCalled();

  // 呼ばれた時の引数が '取得したデータ' かチェック
  expect(mockCallback).toHaveBeenCalledWith('取得したデータ');
});

jest.spyOn()

  • 既存のモジュールの 特定の関数(メソッド)を監視(spy) できる
  • 元の関数の実装を一時的に「監視」し、呼び出し状況を記録できる
  • 必要に応じて、元の実装を「モック(差し替え)」することもできる

🔸①テスト対象のモジュール|logger.ts

export const logger = {
  log: (message: string) => {
    console.log('Log:', message);
  }
};

🔸②これを使う関数|app.ts

import { logger } from './logger';

export function greetUser(name: string) {
  logger.log(`Hello, ${name}!`);
}

🔸③テストコード|logger.test.ts

  • greetUser を呼んだ時にlogger.log が 正しく呼ばれたか
  • 呼ばれた時の引数は 期待どおりか
import * as loggerModule from './logger';
import { greetUser } from './app';

test('greetUserはlogger.logを正しい引数で呼ぶ', () => {
  // logger.log を監視(spy)しつつ、実装は差し替えない(本来のconsole.logは呼ばれる)
  const spy = jest.spyOn(loggerModule.logger, 'log');

  greetUser('Yamada');

  // spyが呼ばれたかチェック
  expect(spy).toHaveBeenCalled();

  // spyが呼ばれたときの引数をチェック
  expect(spy).toHaveBeenCalledWith('Hello, Yamada!');

  spy.mockRestore(); // 監視解除(後続のテストに影響しないように)
});

jest.mock()

  • モジュール全体を丸ごとモック(偽物)に差し替えるための関数
  • 本物の実装を使わずに、テスト用のダミー実装を指定できる
  • 外部APIやファイル読み込みなど、テスト環境で動かしたくない処理を差し替えるのに便利

🔸①テスト対象のモジュール|api.ts

export const fetchData = async () => {
  const response = await fetch('https://example.com/data');
  const data = await response.json();
  return data.message;
};

🔸②これを使う関数|app.ts

import { fetchData } from './api';

export async function showMessage() {
  const message = await fetchData();
  return `メッセージ: ${message}`;
}

🔸③テストコード|api.test.ts

  • テスト時に実際の外部通信(fetch)を行いたくない
  • fetchData の戻り値を自由にコントロールしたい
// app.test.ts
jest.mock('./api', () => ({
  fetchData: jest.fn().mockResolvedValue('モックのメッセージ')
}));

import { fetchData } from './api';
import { showMessage } from './app';

test('showMessageはモックデータを返す', async () => {
  const result = await showMessage();

  expect(fetchData).toHaveBeenCalled(); // fetchDataが呼ばれたかチェック
  expect(result).toBe('メッセージ: モックのメッセージ');
});