1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jestを使ってSpabaseをモックしてテストを書く①

Last updated at Posted at 2026-01-26

はじめに

このプロジェクトでは、React + Jest + Testing Libraryを使用して学習記録アプリのテストを実装しています。この記事では、実際のプロジェクトの設定とテストコードを基に、テスト環境の構築方法とテストの書き方を説明します。

プロジェクト概要

学習記録アプリは、Supabaseをバックエンドとして使用するReactアプリケーションです。ユーザーは学習内容と学習時間を入力し、記録を管理できます。

テスト環境のセットアップ

必要なパッケージ

package.jsonに以下のパッケージが含まれています:

  • jest: テストフレームワーク
  • jest-environment-jsdom: ブラウザ環境のシミュレート
  • @testing-library/react: Reactコンポーネントのテスト
  • @testing-library/jest-dom: DOM要素のマッチャー
  • babel-jest: Babelを使用したJavaScript変換
  • identity-obj-proxy: CSSファイルのモック

設定ファイル

jest.config.mjs

export default {
    testEnvironment: "jsdom",
    moduleNameMapper: {
      "\\.(css|less)$": "identity-obj-proxy",
    },
    setupFilesAfterEnv: ["./jest.setup.js"],
};
  • testEnvironment: "jsdom": ブラウザ環境をシミュレート
  • moduleNameMapper: CSSファイルをモック化
  • setupFilesAfterEnv: テスト実行前に読み込む設定ファイル

jest.setup.js

import "@testing-library/jest-dom";

// dotenvの設定
require("dotenv").config();
  • @testing-library/jest-domのマッチャーを有効化
  • 環境変数の読み込み

.babelrc

{
    "presets": [
        "@babel/preset-env",
        [
            "@babel/preset-react",
            {
                "runtime": "automatic"
            }
        ]
    ]
}
  • ES6+の構文とJSXを変換

モック(Mock)とは?なぜモックを使うのか?

モックとは

モックとは、テスト時に実際のオブジェクトや外部サービスの代わりに使用する「偽物」のオブジェクトです。本物と同じインターフェース(メソッドや戻り値の形式)を持ちながら、テスト用に制御された振る舞いをします。
DBに接続しなくても模擬でDBを操作しているように振る舞う振る舞いを定義する

なぜモックが必要なのか

このプロジェクトでは、Supabase(データベースサービス)をモック化しています。モックを使う理由は以下の通りです:

1. テストの独立性を保つ

実際のSupabaseに接続すると、テストの結果がデータベースの状態に依存してしまいます。例えば:

  • 他の開発者がデータを変更したら、テストが失敗するかもしれない
  • テスト前後でデータベースの状態が変わってしまう

モックを使えば、外部サービスの状態に関係なく、常に同じ条件でテストを実行できます

2. テストを高速に実行する

実際のデータベースへの接続には、ネットワーク通信が発生します。これには時間がかかります。モックを使えば、ネットワーク通信なしで即座にデータを返すため、テストが高速に実行されます。

3. テスト結果を安定させる(再現性)

モックは毎回同じデータを返すように設定できます。これにより:

  • 今日実行しても、明日実行しても、同じ結果が得られる
  • CI/CD環境でも、ローカル環境でも、同じテスト結果になる

テストの再現性は、信頼できるテストを書く上で非常に重要です。

4. 様々なケースをシミュレートできる

モックを使えば、実際には発生させにくい状況を簡単にテストできます:

  • データベース接続エラー
  • 空のデータが返ってくる場合
  • 大量のデータが返ってくる場合
// エラーケースのモック例
select: jest.fn(() => Promise.resolve({ data: null, error: { message: "接続エラー" } }))

5. コストと環境の問題を回避

実際のAPIを呼び出すと:

  • API利用料金が発生する可能性がある
  • テスト環境用のデータベースを用意する必要がある
  • 環境変数やクレデンシャルの設定が必要

モックを使えば、追加のコストや環境設定なしでテストを実行できます

モックの考え方

モックを作る際のポイントは、「テスト対象が期待する振る舞いを再現する」ことです。

このプロジェクトでは、AppコンポーネントがSupabaseの以下のメソッドを使用しています:

  • supabase.from("study-record").select() - データの取得
  • supabase.from("study-record").insert().select() - データの挿入
  • supabase.from("study-record").delete().eq() - データの削除

したがって、モックでもこの構造(メソッドチェーン)を再現し、期待されるデータ形式を返すように設定します。

テストコードの実装

実際のテストファイル: src/test/sample.spec.js

import App from "../index.jsx";
import React from "react";
import '@testing-library/jest-dom'
import { render, screen } from "@testing-library/react";

jest.mock("../supabase.js", () => {
    const mockRecords = [
        {
            id: 1,
            title: "test",
            time: 3,
        }
    ];

    return {
        __esModule: true,
        default: {
            from: jest.fn(() => ({
                select: jest.fn(() => Promise.resolve({ data: mockRecords, error: null })),
                insert: jest.fn(() => ({
                    select: jest.fn(() => Promise.resolve({ data: mockRecords, error: null }))
                })),
                delete: jest.fn(() => ({
                    eq: jest.fn(() => Promise.resolve({ error: null }))
                }))
            }))
        }
    };
});

describe("学習記録アプリ", () => {
    it("タイトルが表示されていること", async () => {
        render(<App />);
        const title = await screen.findByTestId("title");
        expect(title).toHaveTextContent("test");
    });
});

テストの説明

  1. Supabaseのモック: jest.mock()でSupabaseクライアントをモック化し、実際のデータベース接続なしでテストを実行
  2. コンポーネントのレンダリング: render(<App />)でアプリをレンダリング
  3. 要素の取得: screen.findByTestId("title")data-testid="title"を持つ要素を取得(非同期で待機)
  4. アサーション: expect(title).toHaveTextContent("test")でテキスト内容を確認

Supabaseモックのポイント

Supabaseはメソッドチェーン(from().select()など)を使用するため、モックでも同じ構造を再現します:

  • from(): テーブルを指定
  • select(): データ取得
  • insert().select(): データ挿入
  • delete().eq(): データ削除

各メソッドはPromise.resolve()で非同期処理をシミュレートします。

テストの実行

npm test

テストを実行すると、src/test/ディレクトリ内のテストファイルが実行されます。

テストの拡張例

現在のテストは「タイトルが表示されていること」のみをテストしていますが、以下のようなテストを追加できます:

  • 学習記録の一覧表示
  • 学習記録の登録機能
  • 学習記録の削除機能
  • バリデーションエラーの表示
  • 学習時間の合計表示

まとめ

このプロジェクトでは、JestとReact Testing Libraryを使用して学習記録アプリのテストを実装しています。Supabaseのような外部依存はモック化することで、テストを独立させ、高速に実行できるようにしています。

テストを追加・改善することで、コードの品質を保ち、リファクタリング時の安全性を確保できます。

大切なことなのでもう一度いいます。
テストでモックを使う理由は「DBに接続しなくても模擬でDBを操作しているように振る舞う振る舞いを定義する
以上。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?