見出し画像

【Jest_53】 依存ライブラリ(例: axios)をモックする方法は?

Jestで依存ライブラリ(例:axios)をモックする

実践的な使い方・注意点・ユースケース・設計のベストプラクティスまで徹底網羅


この記事でわかること

  • axios のようなサードパーティライブラリのモック方法

  • 自動モックと手動モックの使い分け

  • axios.get など特定のメソッドだけをモックする方法

  • TypeScript での型補完や安全なモック方法

  • jest.mock() の内部動作と注意点


前提:なぜ axios をモックするのか?

テスト対象を純粋に保ちたい

  • 外部通信(HTTPリクエスト)を実行したくない

  • APIの応答が不安定でもテストを安定化させたい

返ってくるデータをコントロールしたい

  • 成功/失敗パターンを自在に再現

  • テストケースに必要な状態を強制的に作る


1. axios を使ったコード例(テスト対象)

// services/userService.ts
import axios from 'axios';

export async function fetchUser(id: number) {
  const response = await axios.get(`/api/users/${id}`);
  return response.data;
}

2. Jest で axios をモックする基本パターン

ステップ①:jest.mock を使って axios をモック化

jest.mock('axios');

この1行で、axios モジュール全体がモック化される
→ axios.get, axios.post など全て jest.fn() に変わる


ステップ②:axios.get の返り値を定義する

// services/userService.test.ts
import axios from 'axios';
import { fetchUser } from './userService';

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>; // 型補完のため

test('fetchUser returns user data', async () => {
  mockedAxios.get.mockResolvedValue({
    data: { id: 1, name: 'Alice' }
  });

  const user = await fetchUser(1);
  expect(user).toEqual({ id: 1, name: 'Alice' });
});

補足:mockResolvedValue / mockRejectedValue

mockResolvedValue(x)
 Promise.resolve(x) の応答
mockRejectedValue(e)
 Promise.reject(e) の応答


3. エラーパターンをテストする(API失敗など)

test('fetchUser throws on failure', async () => {
  mockedAxios.get.mockRejectedValue(new Error('Network error'));

  await expect(fetchUser(1)).rejects.toThrow('Network error');
});

4. axios.create() を使っている場合

コード例(createでカスタムインスタンス作成)

// libs/apiClient.ts
import axios from 'axios';
export const api = axios.create({ baseURL: '/api' });
// services/productService.ts
import { api } from '../libs/apiClient';

export async function fetchProduct(id: number) {
  const res = await api.get(`/products/${id}`);
  return res.data;
}

モック方法

// services/productService.test.ts
import { api } from '../libs/apiClient';

jest.mock('../libs/apiClient', () => ({
  api: {
    get: jest.fn()
  }
}));

test('fetchProduct works', async () => {
  (api.get as jest.Mock).mockResolvedValue({
    data: { id: 1, name: 'Shoes' }
  });

  const result = await fetchProduct(1);
  expect(result.name).toBe('Shoes');
});

5. 型安全にモックしたい(TypeScript)

import axios from 'axios';
import { jest } from '@jest/globals';

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

// mockedAxios.get → mock関数として型補完が効く

6. よくある失敗とその対処法

axios.get is not a function
 jest.mock() が import より後
 mock を import より前に書く
mockResolvedValue が undefined
 モックが有効になっていない
 as jest.Mocked<typeof axios> を使って型強制
型エラーになる
 TS の型が合っていない
 jest.Mocked<モジュール> を使う


7. axios モックのバリエーション集(Tips)

複数のレスポンスを順番に返す

mockedAxios.get
  .mockResolvedValueOnce({ data: { id: 1 } })
  .mockResolvedValueOnce({ data: { id: 2 } });

axios.post / put / delete のモック

mockedAxios.post.mockResolvedValue({ data: { ok: true } });
mockedAxios.delete.mockResolvedValue({ status: 204 });

レスポンスステータスやheaders付きで返す

mockedAxios.get.mockResolvedValue({
  status: 200,
  headers: { 'x-custom-header': 'abc' },
  data: { id: 1 }
});

8. 後始末:テスト間で状態が残らないように

beforeEach(() => {
  jest.clearAllMocks();
});

これを入れないと 前のテストの呼び出しが干渉することがあります。


まとめ

・jest.mock('axios') で axios 全体をモック化
・as jest.Mocked<typeof axios> で型を補完
・mockResolvedValue / mockRejectedValue で柔軟に制御
・axios.create() 対応にはモジュールごとモックする
・毎回 jest.clearAllMocks() で状態初期化



いいなと思ったら応援しよう!