プログラミングマガジン

プログラミングを中心にIT技術をできるだけわかりやすくまとめます。

  • ホーム
  • React
  • 【React】「API」の実行をテストしたい場合(直接呼ぶ、axiosのjestモック、m…
 
 
     
  • サーバー言語  
    • Python
    • Ruby
    • PHP
    • SQL
  •  
  • インフラ  
       
    • AWS
    •  
    • 基本
    • Git
  • Web
       
    • Web開発
    • JavaScript
    • Vue.js
    • React
  •  
  • 設計  
       
    • 実装設計
    • DB設計
  • 問い合わせ
  

【React】「API」の実行をテストしたい場合(直接呼ぶ、axiosのjestモック、mswを使う。)

02.11

  • miyabisan2
  • コメントを書く

この記事は2分で読めます

APIを直接呼ぶ場合

例えば、Renderというコンポーネントが初期表示時にUseEffectを使用してAPIで表示するデータを取得する処理があった場合は下記のようなテストを書きます。

1
2
3
4
5
6
7
8
9
10
11
import React from "react";
import { render, screen } from "@testing-library/react";
import Render from "./Render";
 
describe("API", () => {
  it("APIテスト", async () => {
    render(<Render />);
    expect(screen.queryByText(/テスト/)).toBeNull(); //APIの結果が取得されないこと。
    expect(await screen.findByText(/テスト/)).toBeInTheDocument(); //APIの結果が取得されること。
  });
});

awaitをする場合はAPIの実行結果を待つのでデータが表示されることをチェックし、awaitをしない場合はAPIの結果を待たないのでデータが表示されないというようなテストケースを作ることになります。

jest.mock("axios")を使ってモック化する。(最近は非推奨)

axiosをモック化する場合は以下のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import {render,screen} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import axios from "axios";
import {Render} from "./Render"
 
const user = userEvent.setup();
 
jest.mock("axios");
const mockAxios = jest.mocked(axios);
describe("axios mock",()=>{
    beforeEach(()=>{
        mockAxios.get.mockReset();
    });
 
    it("入力フォームに入力した内容でAPIリクエストが送信される",async ()=>{
        const userInfo = {
            id:1,
            name: "Taro"
        };
        const resp = { data: userInfo };
        mockAxios.get.mockResolvedValue(resp);
 
        render(<Render />)
 
        const input = screen.getByRole("textbox");
        await user.type(input,userInfo.name);
        const button = screen.getByRole("button");
        await user.click(button);
        // コンポーネント側で「/api/users?query="ユーザー名"」というAPIをaxiosで叩いている。
        expect(mockAxios.get).toHaveBeenCalledWith(`/api/users?query=${userInfo.name}`)
    })
})

mock service workerを使ってモックを使う場合(最近は推奨)

mock service workerという物を使うことが公式で推奨されています。

axiosのモックの問題点

一言でいえば、axios自体をmock化しているのでaxiosとの依存関係がなくなってしまう。

  • axiosをそのままmockしているのでaxiosのモジュール自体にバグが入った場合でも動いてしまう。
  • axiosのライブラリ自体が変わってしまい戻り値が変わった場合でも動いてしまう。

mswを使えばaxios自体をモックせず、axiosと通信をmswがインターセプトしてモック値を返します。なので、モック化されていないaxiosと通信することになるので上記の問題を解消できるとのことです。

インストール

1
npm install msw --save-dev

実装

例えば、GETリクエストであれば下記のような感じになります。APIのエンドポイントを指定すれば外部のAPIではなくこちらのモックの内容を返してくれます。下記のセットアップをすれば、テスト対象のコンポーネント内でAPIエンドポイントにアクセスすればモックサーバーが結果を返してくれます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { render, screen, cleanup } from "@testing-library/react";
import { rest } from "msw";
import { setupServer } from "msw/node";
 
const server = setupServer(
  rest.get("APIのエンドポイントのURL", (req, res, ctx) => {
    return res(ctx.status(200), ctx.json({ name:"太郎" }));
  })
);
 
beforeAll(() => server.listen());
afterEach(() => {
  server.resetHandlers();
  cleanup();
});
afterAll(() => server.close());

リクエストのことで、リクエストパラメータを追加したい場合とかに使ったりします。

res

上の例で言えばGETに対するレスポンスのことです。

ctx

コンテキストのことです。jsonなどレスポンスのオブジェクトのダミーの内容を定義できます。

beforeAll(() => server.listen());

全てのテストコード実行前にモックサーバーを起動します。

server.resetHandlers();

サーバーを一旦リセットします。各テストコードが終わる度にこれを呼ぶ決まりになっているので、afterEachと一緒に記述することが定例になっています。各テストケース間で副作用が起こらないようにするための記述です。

afterAll(() => server.close());

全てのテストコード実行後にモックサーバーを終了します。各テストケース間で副作用が起こらないようにするための記述です。

複数のAPIエンドポイントを定義したい場合

以下のようにsetupServerに対して

1
2
3
4
5
6
7
8
9
10
const handlers = [
  rest.post('エンドポイントURL1', (req, res, ctx) => {
    return res(ctx.status(200), ctx.json({ token: 'abc123' }));
  }),
  rest.post('エンドポイントURL2', (req, res, ctx) => {
    return res(ctx.status(201));
  }),
];
 
const server = setupServer(...handlers);

あるテストケースだけエンドポイントのレスポンス結果を変えたい場合

1
2
3
4
5
6
7
8
9
10
11
  it('あるエンドポイントだけ変える', async () => {
    server.use(
      rest.post('http://localhost:8000/api/auth/', (req, res, ctx) => {
        return res(ctx.status(400));
      })
    );
    render(
        <xxx/>
    );
      処理
  });

itの中で、server.useを使います。そうすることで特定のit内でのみ特定のエンドポイントの返す結果を変えることが可能です。

用途

あるテストケースだけ意図的に処理を失敗させたい場合などに使えたりします。

スポンサーリンク
  • 2021 02.11
  • miyabisan2
  • コメントを書く
  • React
  • Tweets Twitter
  • このエントリーをはてなブックマークに追加
  • LINEで送る

関連記事

  1. 2021 02.09

    【React】「material-ui」について

  2. 2021 07.23

    【React/Redux】「Presentational Component」と「Container Component」、「HOC」

  3. 2021 05.04

    【React/Redux】「Redux Tool Kit」の導入(createSlice)

  4. 2021 07.22

    【React】「useMemo/useCallback」について

  5. 2022 11.09

    【React】「Material-UI」のデザイン手法(Theme、Box、Container、Typographyなど)

  6. 2021 02.08

    【Redux】「Reducer」、「Action」の実装方法

  • コメント ( 0 )
  • トラックバック ( 0 )
  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

返信をキャンセルする。

【React】props、「モック」を使ったテスト、R…

【Redux】「redux-saga」で非同期処理

RETURN TOP

著者プロフィール

エンジニア歴10年で過去に業務系、Webデザイン、インフラ系なども経験あります。現在はWeb系でフロントエンド開発中心です。

詳細なプロフィールはこちら

スポンサーリンク

カテゴリー

  • Android
  • AngularJS
  • API
  • AWS
  • C++
  • CSS
  • cursor
  • C言語
  • DDD
  • DevOps
  • Django
  • Docker
  • Figma
  • Git
  • GitLab
  • GraphQL
  • gRPC
  • Hasura
  • Java
  • JavaScript
  • Kubernetes
  • Laravel
  • linux
  • MySQL
  • Next.js
  • nginx
  • Node.js
  • NoSQL
  • Nuxt.js
  • Oracle
  • PHP
  • Python
  • React
  • Redux
  • Rspec
  • Ruby
  • Ruby on Rails
  • Sass
  • Spring Framework
  • SQL
  • TypeScript
  • Unity
  • Vue.js
  • Webサービス開発
  • Webデザイン
  • Web技術
  • インフラ
  • オブジェクト指向
  • システム開発
  • セキュリティ
  • その他
  • データベース
  • デザインパターン
  • テスト
  • ネットワーク
  • プログラミング全般
  • マイクロサービス
  • マイクロソフト系技術
  • マルチメディア
  • リファクタリング
  • 副業
  • 未分類
  • 業務知識
  • 生成AI
  • 設計
  • 関数型言語
RETURN TOP

Copyright ©  プログラミングマガジン | プライバシーポリシー