API 呼び出しのモックやスタブを伴う単体テストを記述するのは、大変なことだと感じるかもしれません。私自身もその経験がありました。この記事では、テスト中に API リクエストを模擬するためのより簡単で効率的な方法を説明します。
本題に入る前に、使用するツールのリストを以下に示します。
- 反応
- React テスト ライブラリ
- 冗談
- クラコ: >後で jest 設定を拡張するためにこれが必要になります
- MSW (模擬サービスワーカー)
すべてに詳しくなくても心配する必要はありません。各ステップについて説明しますので、そのまま従ってください。
プロジェクトへの Github リンクは次のとおりです
概要
Json Placeholder API を使用して Todo のリストを取得して表示するシンプルな React アプリを構築します。このプロジェクトでは、次のことを検証するテスト シナリオを作成します:
- API リクエストの進行中、アプリは読み込み状態を表示します。
- リクエストが失敗した場合は、エラー メッセージが表示されます。
- API からのデータのリストが正しく表示されるようにします。
- リクエストが成功した場合にフィードバックが提供されますが、データは返されません。
このガイドでは 2 つの主要なアプローチについて説明します。
- API 呼び出しをモックする従来の方法
- MSW (Mock Service Worker) を使用した最新のアプローチ
始めましょう!
アプリの構築を開始するには、次の手順に従います:
1.新しい React アプリを作成します: 次のコマンドを実行して React アプリケーションを作成します:
npx create-react-app msw-example
2.アプリケーションを起動します: セットアップ後、プロジェクト フォルダーに移動して次を実行します:
npm start
3.必要なパッケージをインストールします: 次に、クライアント側のデータを管理するために @tanstack/react-query をインストールします:
npm install @tanstack/react-query
React Query (Tanstack Query) は、キャッシュ、同期、データのフェッチなどのサーバー側の状態管理の処理に役立ちます。詳細については、公式ドキュメントをご覧ください
これで、アプリのロジックの作成を開始し、データの取得を効率的に管理するために React Query を設定できるようになりました。セットアップ後の様子は次のとおりです。
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { Todos } from "components/Todos"; const queryClient = new QueryClient(); function App() { return ( <queryclientprovider client="{queryClient}"> <div data-testid="app" classname="App"> <todos></todos> </div> </queryclientprovider> ); } export default App;
次に、Todo のリストをレンダリングする Todos コンポーネントを作成します。
Todos.js
import { useQuery } from "@tanstack/react-query"; import { getTodos } from "api/todo"; export function Todos() { const { data, isError, isLoading } = useQuery({ queryFn: getTodos, queryKey: ["TODOS"], }); if (isLoading) { return <p>loading todo list</p>; } if (isError) { return <p>an error occurred fetching todo list</p>; } return ( <div> {Boolean(data.length) ? ( <ol> {data.map((item) => ( <li key="{item.id}">{item.title}</li> ))} </ol> ) : ( <p>You do not have todos created yet</p> )} </div> ); }
すべての設定が完了したので、前に概説したシナリオのテストの作成を開始しましょう。まず、これを、すでに慣れ親しんだ従来のアプローチ、つまり Jest
を使用して API 呼び出しをモックして使用して実装します。Github リポジトリをチェックアウトして、フォローしてください
API 呼び出しをモックする従来の方法
React と Jest はすぐに使用できる状態でシームレスに連携するため、少なくとも現時点では追加の構成やセットアップは必要ありません。 Todo.js コンポーネントの隣に Todos.test.js という名前のファイルを作成し、そこに Todos コンポーネントをインポートしてテストを作成します。
getTodos という関数があり、API 呼び出しを行って Todo のリストを取得し、応答を返す役割を果たします。
export async function getTodos() { const response = await fetch("https://jsonplaceholder.typicode.com/todos", { headers: { "Content-Type": "application/json", }, }); if (!response.ok) { const res = await response.json(); throw new Error(res.message || response.status); } return response.json(); }
Todos.test.js ファイルで、Todos コンポーネントをインポートし、React Query プロバイダーのラッパーを提供するユーティリティ関数を作成する必要があります。これにより、Todos コンポーネントとその子は、テストでサーバーの状態を管理するために React-Query を使用できるようになります。
import { render, screen, waitFor, within } from "@testing-library/react"; import { Todos } from "./Todos"; import { reactQueryWrapper } from "utils/reactQueryWrapper"; import { getTodos } from "api/todo"; const { wrapper, queryCache } = reactQueryWrapper();
次に、getTodos 関数をモックする必要があります。これにより、各テスト シナリオの戻り値を指定できるようになり、テスト中に関数が返すデータを制御できるようになります。さらに、以前のテスト ケースで残ったデータが確実にクリーンアップされるため、各テスト ケースは白紙の状態から開始されます。
コードサンプル
jest.mock("api/todo", () => ({ getTodos: jest.fn(), })); afterEach(() => { queryCache.clear(); jest.clearAllMocks(); });
Todos.test.js
import { render, screen, waitFor, within } from "@testing-library/react"; import { Todos } from "./Todos"; import { reactQueryWrapper } from "utils/reactQueryWrapper"; import { getTodos } from "api/todo"; const { wrapper, queryCache } = reactQueryWrapper(); jest.mock("api/todo", () => ({ getTodos: jest.fn(), })); afterEach(() => { queryCache.clear(); }); afterEach(() => { jest.clearAllMocks(); });
最初のテスト シナリオ: 読み込み状態をレンダリングします
リクエストの進行中にコンポーネントが読み込み状態を正しく表示することを確認したいと思います。
test("Renders loading state", () => { getTodos.mockImplementation(() => { return new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); }); }); render(<todos></todos>, { wrapper }); const loadingText = screen.getByText("loading todo list"); expect(loadingText).toBeInTheDocument(); });
2 番目のテスト シナリオ: リクエストが失敗した場合、またはネットワーク エラーが発生した場合にエラー状態をレンダリングします
API リクエストが失敗した場合、またはネットワーク エラーが発生した場合に、コンポーネントがエラー状態を正しく表示することを確認したいと考えています。
test("Renders error state when request fails or there is network error", async () => { getTodos.mockImplementationOnce(() => { return new Promise((resolve, reject) => { reject(); }); }); render(<todos></todos>, { wrapper }); await screen.findByText("an error occurred fetching todo list"); expect( screen.getByText("an error occurred fetching todo list") ).toBeInTheDocument(); });
3 番目のテスト シナリオ: ToDo リストをレンダリングします
リクエストが成功したときに、コンポーネントが todo のリストを正しくレンダリングすることを確認したいと思います。
test("Renders list of todos", async () => { getTodos.mockImplementation(() => { return Promise.resolve([ { id: 1, title: "Exercise" }, { id: 2, title: "Cook" }, ]); }); render(<todos></todos>, { wrapper }); const loadingText = screen.queryByText("loading todo list"); await waitFor(() => expect(loadingText).not.toBeInTheDocument()); const list = screen.getByRole("list"); expect(list).toBeInTheDocument(); expect(within(list).getAllByRole("listitem")).toHaveLength(2); });
4 番目のテスト シナリオ: todo リストをレンダリングします
API リクエストが todo の空のリストを返したときに、コンポーネントがフィードバック メッセージを正しくレンダリングすることを確認したいと思います。
test("Renders feedback message when user has an empty list of todos", async () => { getTodos.mockImplementationOnce(() => { return Promise.resolve([]); }); render(<todos></todos>, { wrapper }); await waitFor(() => expect(screen.queryByText("loading todo list")).not.toBeInTheDocument() ); expect( screen.getByText("You do not have todos created yet") ).toBeInTheDocument(); });
Great! Now that we've covered mocking API calls with Jest, let’s explore a better approach using Mock Service Worker (MSW). MSW provides a more elegant and maintainable way to mock API calls by intercepting network requests at the network level rather than within your tests.
Introducing MSW (Mock Service Worker)
Mock Service Worker (MSW) is an API mocking library designed for both browser and Node.js environments. It allows you to intercept outgoing requests, observe them, and provide mocked responses. MSW helps you simulate real-world scenarios in your tests, making them more robust and reliable.
Read more about MSW
Setting Up MSW
Step 1: Install MSW using the following command:
npm install msw@latest --save-dev
Step 2: Set up the environment you wish to intercept requests in—either Browser or Node. Before doing so, create a mock directory within your src directory. Inside this directory, you'll create the following files and directories:
browser.js: Handles request interception in the browser environment.
server.js: Handles request interception in the Node.js environment.
handlers: A directory containing files that define the API endpoints to intercept.
Here’s how your folder structure should look:
src/ └── mock/ ├── browser.js ├── server.js └── handlers/
This setup ensures that you have a clear organization for intercepting and handling requests in both browser and Node.js environments using MSW.
Browser Environment Setup
To set up MSW for intercepting requests in the browser, follow these steps:
1. Create the browser.js File
In your src/mock directory, create a file named browser.js. This
file will set up the MSW worker to intercept requests in the
browser environment.
// src/mock/browser.js import { setupWorker } from 'msw/browser'; // Create a worker instance to intercept requests export const worker = setupWorker();
2. Generate the mockServiceWorker.js File
This file is required for MSW to function properly in the browser.
Generate it using the following command from the root directory of
your application:
npx msw init <public_dir> --save </public_dir>
This command initializes the MSW service worker and places the mockServiceWorker.js file into the public directory of your React app.
3. Start the Service Worker
Import and start the worker in your application entry point
(typically index.js or App.js).
// src/index.js import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; if (process.env.NODE_ENV === "development") { const mswState = localStorage.getItem("mswState") === "enabled"; if (mswState) { const { worker } = require("./mocks/browser"); worker.start(); window.__mswStop = worker.stop; } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <react.strictmode> <app></app> </react.strictmode> );
4. Verify the Setup
To ensure that the service worker is correctly set up, navigate to
the URL of your application in the browser:
http://localhost:3000/mockServiceWorker.js
You should see the service worker script displayed in your browser. This confirms that the service worker is correctly installed and ready to intercept requests.
If your MSW setup is correct and enabled, you should see a console message indicating that MSW is active. Your browser console should display logs similar to this:
These logs confirm that the MSW service worker is properly intercepting network requests and is ready to mock API responses according to the handlers you’ve defined.
Node Environment Setup
To set up MSW for intercepting requests in a Node.js environment (for example, in server-side tests), follow these steps:
Step 1: Create the server.js File
In the src/mock directory, create a file named server.js. This file sets up the MSW server to intercept requests in a Node.js environment.
// src/mock/server.js import { setupServer } from "msw/browser"; // Create a server instance with the defined request handlers export const server = setupServer();
Step 2: Define the API Handlers
Create a file named posts.js in the handlers directory.This file will describe the APIs you want to intercept and the mock responses.
// src/mock/handlers/posts.js import { http, HttpResponse } from "msw"; export const postHandlers = [ // Handler for GET /todos request http.get("https://jsonplaceholder.typicode.com/todos", () => { return HttpResponse.json([ { id: 1, title: "totam quia non" }, { id: 2, title: "sunt cum tempora" }, ]); }), ];
Here, we're defining that when MSW intercepts a GET request to https://jsonplaceholder.typicode.com/todos, it should respond with a 200 status code and the provided JSON data.
Step 3: Hook Handlers to the Browser Worker
Update the browser.js file to include the defined handlers.
import { setupWorker } from "msw/browser"; import { postHandlers } from "./handlers/posts"; export const worker = setupWorker(...postHandlers);
Step 4: Hook Handlers to the Node Server
Ensure the handlers are also used in the Node.js environment by updating the server.js file.
import { setupServer } from "msw/node"; import { postHandlers } from "./handlers/posts"; export const server = setupServer(...postHandlers);
With these configurations in place, your MSW setup is complete and ready for both browser and Node.js environments. Congratulations on completing the setup! ?
Using MSW in our Tests
To use MSW in your tests, you need to set up your test environment to utilize the mock server for intercepting API calls. Here’s a guide to setting up and writing tests using MSW with your Todos component.
Create the Test File
Create a new file named Todos.MSW.test.js next to your
Todos.jscomponent. This file will contain your tests that
utilize MSW for mocking API responses.Set Up Test Environment
In your Todos.MSW.test.js file, import the necessary modules and
set up the environment for using MSW with your tests. Below is an
example setup:
import { render, screen, waitFor, within } from "@testing-library/react"; import { http, delay, HttpResponse } from "msw"; import { Todos } from "./Todos"; import { reactQueryWrapper } from "utils/reactQueryWrapper"; import { server } from "mocks/server"; const { wrapper, queryCache } = reactQueryWrapper(); afterEach(() => { queryCache.clear(); }); afterEach(() => { jest.clearAllMocks(); }); beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close());
First Test Scenario: Renders loading state
We want to verify that our component correctly displays the loading state while the request is in progress.
test("Renders loading state", () => { server.use( http.get("https://jsonplaceholder.typicode.com/todos", async () => { await delay(1000); return HttpResponse.json([]); }) ); render(<todos></todos>, { wrapper }); const loadingText = screen.getByText("loading todo list"); expect(loadingText).toBeInTheDocument(); });
Second Test Scenario: Renders error state when request fails or there is network error
We want to verify that the component correctly renders an error state when the API request fails or encounters a network error.
test("Renders error state when request fails or there is network error", async () => { server.use( http.get("https://jsonplaceholder.typicode.com/todos", async () => { return HttpResponse.json([], { status: 500, }); }) ); render(<todos></todos>, { wrapper }); await screen.findByText("an error occurred fetching todo list"); expect( screen.getByText("an error occurred fetching todo list") ).toBeInTheDocument(); });
Third Test Scenario: Renders list of todos
We want to verify that our component correctly renders the list of todos when the request is successful.
test("Renders list of todos", async () => { render(<todos></todos>, { wrapper }); const loadingText = screen.queryByText("loading todo list"); await waitFor(() => expect(loadingText).not.toBeInTheDocument()); const list = screen.getByRole("list"); expect(list).toBeInTheDocument(); expect(within(list).getAllByRole("listitem")).toHaveLength(2); });
Fourth Test Scenario: Renders list of todos
We want to verify that your component correctly renders a feedback message when the API request returns an empty list of todos.
test("Renders feedback message when user has an empty list of todos", async () => { server.use( http.get("https://jsonplaceholder.typicode.com/todos", () => { return HttpResponse.json([]); }) ); render(<todos></todos>, { wrapper }); await waitFor(() => expect(screen.queryByText("loading todo list")).not.toBeInTheDocument() ); expect( screen.getByText("You do not have todos created yet") ).toBeInTheDocument(); });
Final Thoughts
Mocking API calls is crucial for effective testing, allowing you to simulate different scenarios without relying on real backend services. While traditional Jest mocking can be effective, MSW offers a more sophisticated solution with better support for various environments and more realistic request handling.
Here are a few tips to keep in mind:
Choose the Right Tool: Use MSW for a more comprehensive
solution that integrates seamlessly with your React application,
especially when dealing with complex request handling.Organize Your Handlers: Keep your API handlers well-organized
and modular to make them easier to maintain and extend.Clean Up After Tests: Ensure that your tests clean up properly
by resetting handlers and clearing mocks to avoid interference
between tests.Verify Setup: Always check your setup by inspecting the network
requests and responses to ensure that everything is working as
expected.
By incorporating MSW into your testing strategy, you'll achieve more reliable and maintainable tests, leading to a smoother development experience and higher quality software.
Happy testing! ?
以上がネットワークリクエストのモックが簡単に: Jest と MSW の統合の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

JavaScriptフレームワークのパワーは、開発を簡素化し、ユーザーエクスペリエンスとアプリケーションのパフォーマンスを向上させることにあります。フレームワークを選択するときは、次のことを検討してください。1。プロジェクトのサイズと複雑さ、2。チームエクスペリエンス、3。エコシステムとコミュニティサポート。

はじめに私はあなたがそれを奇妙に思うかもしれないことを知っています、JavaScript、C、およびブラウザは正確に何をしなければなりませんか?彼らは無関係であるように見えますが、実際、彼らは現代のウェブ開発において非常に重要な役割を果たしています。今日は、これら3つの間の密接なつながりについて説明します。この記事を通して、JavaScriptがブラウザでどのように実行されるか、ブラウザエンジンでのCの役割、およびそれらが協力してWebページのレンダリングと相互作用を駆動する方法を学びます。私たちは皆、JavaScriptとブラウザの関係を知っています。 JavaScriptは、フロントエンド開発のコア言語です。ブラウザで直接実行され、Webページが鮮明で興味深いものになります。なぜJavascrを疑問に思ったことがありますか

node.jsは、主にストリームのおかげで、効率的なI/Oで優れています。 ストリームはデータを段階的に処理し、メモリの過負荷を回避します。大きなファイル、ネットワークタスク、リアルタイムアプリケーションの場合。ストリームとTypeScriptのタイプの安全性を組み合わせることで、パワーが作成されます

PythonとJavaScriptのパフォーマンスと効率の違いは、主に以下に反映されています。1)解釈された言語として、Pythonはゆっくりと実行されますが、開発効率が高く、迅速なプロトタイプ開発に適しています。 2)JavaScriptはブラウザ内の単一のスレッドに限定されていますが、マルチスレッドおよび非同期I/Oを使用してnode.jsのパフォーマンスを改善でき、両方とも実際のプロジェクトで利点があります。

JavaScriptは1995年に発信され、Brandon Ikeによって作成され、言語をCに実現しました。 2。JavaScriptのメモリ管理とパフォーマンスの最適化は、C言語に依存しています。 3. C言語のクロスプラットフォーム機能は、さまざまなオペレーティングシステムでJavaScriptを効率的に実行するのに役立ちます。

JavaScriptはブラウザとnode.js環境で実行され、JavaScriptエンジンに依存してコードを解析および実行します。 1)解析段階で抽象的構文ツリー(AST)を生成します。 2)ASTをコンパイル段階のバイトコードまたはマシンコードに変換します。 3)実行段階でコンパイルされたコードを実行します。

PythonとJavaScriptの将来の傾向には、1。Pythonが科学コンピューティングの分野での位置を統合し、AI、2。JavaScriptはWebテクノロジーの開発を促進します。どちらもそれぞれのフィールドでアプリケーションシナリオを拡大し続け、パフォーマンスをより多くのブレークスルーを行います。

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。


ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

SublimeText3 中国語版
中国語版、とても使いやすい

Dreamweaver Mac版
ビジュアル Web 開発ツール

ホットトピック









