メインコンテンツへスキップ

MSWとは?統合テストでAPIモックを行う方法|Next.js対応で徹底解説

·1899 文字·4 分
フロントエンドの統合テストにおいて、最大の懸念事項は 「API通信の不安定さ」 です。 外部APIに依存したテストは、ネットワーク環境やサーバーの状態に左右され、メンテナンスコストを増大させます。

これらの問題を解決し、実装に依存せず、かつ本番に近い環境でテストを行うためのデファクトスタンダードが MSW (Mock Service Worker) です。

この記事では、Next.js環境におけるMSWのセットアップから、実務で役立つ高度なモック手法までを徹底解説します。


1. MSWとは?なぜ他の手法より優れているのか
#

MSW(Mock Service Worker)は、ネットワークレベルでHTTPリクエストをインターセプト(横取り)してモックするライブラリです。

モック手法の比較
#

手法インターセプト層メリットデメリット
jest.mock / spyOn言語レベル (JS/TS)設定が簡単実装コードに強く依存する
nockNode.js httpモジュール実装への依存が少ないブラウザ環境で動かない
MSWネットワークレベル実装・環境を問わず、本番に近い挙動初期設定がやや複雑

MSWはブラウザでは Service Worker を、Node.js環境では インターセプター を使用するため、同じハンドラをテスト環境(Vitest/Jest)と開発環境(Storybook/ブラウザ)で共有できるという圧倒的な強みがあります。


2. MSWの仕組み:どうやって通信を横取りするのか
#

MSWは実際のネットワークリクエストが外に出る直前でキャッチします。

  1. コンポーネントが fetch("/api/user") を実行。
  2. MSWがリクエストを検知。
  3. 定義された Handler にURLとメソッドが一致するものがあるか確認。
  4. 一致すれば、定義された モックレスポンス を返却。

これにより、コンポーネント側は「実際のAPIと通信している」と完全に信じ込んだ状態で動作します。


3. 【実践】Next.js環境への導入手順
#

最新の MSW v2 を前提としたセットアップを紹介します。

インストール
#

npm install msw --save-dev

ハンドラ(Handlers)の定義
#

ドメインごとに分割して管理するのが保守性を高めるコツです。

// src/mocks/handlers/user.ts
import { http, HttpResponse } from "msw";

export const userHandlers = [
  http.get("/api/user", () => {
    return HttpResponse.json({
      id: "u-001",
      name: "テストユーザー",
      email: "[email protected]"
    });
  }),
];

テスト環境(Node.js)の設定
#

// src/mocks/node.ts
import { setupServer } from "msw/node";
import { userHandlers } from "./handlers/user";

export const server = setupServer(...userHandlers);

グローバル設定(Vitest / Jest)
#

テストごとにハンドラをリセットし、テスト間の干渉を防ぎます。

// vitest.setup.ts
import { beforeAll, afterAll, afterEach } from "vitest";
import { server } from "./src/mocks/node";

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

4. 高度なモックテクニック
#

実務では「正常系」だけでなく、様々なケースをシミュレートする必要があります。

4.1 テストごとにレスポンスを上書きする
#

特定のテストケースだけエラー(500)を返したい場合は server.use() を使います。

test("サーバーエラー時にエラーメッセージが表示されること", async () => {
  server.use(
    http.get("/api/user", () => {
      return new HttpResponse(null, { status: 500 });
    })
  );

  render(<UserPage />);
  expect(await screen.findByText("通信エラーが発生しました")).toBeInTheDocument();
});

4.2 ローディング(遅延)のシミュレーション
#

非同期処理の待機中のUIを確認したい場合、delay を使用します。

http.get("/api/user", async () => {
  await delay(1000); // 1秒遅延
  return HttpResponse.json({ name: "遅延ユーザー" });
});

5. Next.js App Router での注意点
#

Next.js 13+ の Server Components (RSC)fetch を使用する場合、コードはサーバーサイド(Node.js環境)で実行されます。このため、MSWもブラウザ用の setupWorker ではなく、Node用の setupServer が適用されている必要があります。

重要

Next.jsのネイティブ fetch は、デフォルトでキャッシュが効くことがあります。テスト環境ではキャッシュの影響を排除するため、必要に応じてキャッシュ無効化の設定を確認してください。


6. ベストプラクティス:型安全なモック
#

TypeScriptを使用している場合、APIの型定義をMSWのハンドラでも活用しましょう。

import { http, HttpResponse, PathParams } from "msw";
import { UserType } from "@/types/user";

export const handler = http.get<PathParams, never, UserType>(
  "/api/user", 
  () => {
    return HttpResponse.json({ id: "1", name: "Safe User" });
  }
);

型を適用することで、APIのレスポンス形式が変更された際にテストコード(モック)側の不整合にいち早く気づくことができます。


7. まとめ
#

MSWを導入することで、フロントエンドの統合テストは「外部への依存」から解放され、高い信頼性と保守性を手に入れることができます。

  • ネットワークレイヤーでモック するため、実装(axios / fetch)に左右されない。
  • ハンドラの共有 により、Storybookや開発環境でも同じモックが使える。
  • server.use による柔軟なレスポンス制御。

モダンなNext.js開発において、MSWはもはや「選択肢」ではなく「必須」のツールと言えるでしょう。


著者
ゆーふー
Web開発、インフラ、AI技術に興味があるエンジニアです。日々の学びを記録しています。

関連記事

👤 運営者プロフィール

運営者プロフィール画像

ゆーふー

メガベンチャーで働く現役Webエンジニア(歴約2年)。
フロントエンドからインフラ構築、セキュリティ対策まで、実務で得た「現場のリアルな技術知見」を発信しています。