なぜテストを書くべきか|テストの価値
「テストを書く時間がない」「動くコードにテストは不要」という声をよく聞きますが、中長期的には「テストがないコードの維持コスト」の方が圧倒的に高くつきます。テストが整備されていれば、リファクタリング・新機能追加時の既存機能への影響を素早く確認でき、自信を持ってコードを変更できます。
テストを書くメリット:
・バグの早期発見(本番環境でバグを発見するより開発時の方が修正コストが低い)
・仕様のドキュメントとして機能(テストコードを読むと動作仕様が理解できる)
・リファクタリングへの自信(テストがあれば安心して改善できる)
・チーム開発での品質担保(CIでテストが通ることを合流の条件にできる)
JestとVitestの選び方
JavaScriptのテストフレームワークとして最も広く使われているJestと、Viteを使ったモダンなプロジェクトで急速に普及しているVitestの使い分けを解説します。
| 項目 | Vitest(推奨) | Jest(老舗・安定) |
|---|---|---|
| 設定の簡単さ | Vite と統合済みで設定がシンプル | BabelやTransform設定が必要 |
| 実行速度 | 大規模テストでJestより高速 | 標準的な速度 |
| API互換 | Jest API とほぼ互換、移行が容易 | — |
| 向くプロジェクト | Next.js・Vite・SvelteKit | Create React App・古い構成 |
| リソース | 急速に普及中 | 最も広く使われ情報量が多い |
新規プロジェクトにはVitestを推奨します。JestからVitestへの移行は、設定ファイルの変更と一部のAPIの差分対応で可能です。
ユニットテストの書き方
関数・ユーティリティのユニットテストの基本的な書き方を解説します。
テストの基本構造(AAAパターン):
Arrange(準備)→ Act(実行)→ Assert(検証)の3ステップが基本です。
よく使うmatcher一覧:
| matcher | 用途 |
|---|---|
| toBe | プリミティブ値の等価チェック(厳密) |
| toEqual | オブジェクト・配列の内容チェック |
| toBeTruthy / toBeFalsy | 真偽チェック |
| toBeNull / toBeUndefined | null / undefined チェック |
| toContain | 配列・文字列に値が含まれるか |
| toThrow | 例外がスローされるか |
| toHaveBeenCalledWith | モック関数が引数付きで呼ばれたか |
非同期テストの書き方:
async/awaitを使った非同期テスト・Promise.resolves/rejectsを使ったPromiseのテスト。APIのモック(msw・jest.fn())の活用。
React Testing Libraryでコンポーネントテスト
Reactコンポーネントのテストには「実装の詳細ではなくユーザーの振る舞い」を検証するアプローチが重要です。React Testing Library(RTL)はこの思想に基づいたテストライブラリです。
RTLの基本的な使い方:
①renderでコンポーネントを描画
②screen.getByRole・getByText・getByLabelTextなどでDOM要素を取得
③userEvent.click・type などでユーザー操作をシミュレート
④expect(element).toBeInTheDocument()等でアサーション
クエリの優先順位(RTLの推奨):
| 順位 | クエリ | 使い時 |
|---|---|---|
| 1 | getByRole | アクセシビリティロール(button・heading等)で取得 |
| 2 | getByLabelText | フォーム要素をラベルで取得 |
| 3 | getByPlaceholderText | 入力欄をプレースホルダで取得 |
| 4 | getByText | 表示テキストで取得 |
| 5 | getByTestId | 最終手段(A11yクエリが使えない時) |
テストの品質を高めるための実践テクニック
テストを書く上で知っておくべき実践的なテクニックを紹介します。
モックの活用:
・外部APIのモック(msw/mswjs):APIリクエストをインターセプトしてモックレスポンスを返す
・モジュールのモック(vi.mock・jest.mock):依存モジュールを置き換える
・spyOn:関数の呼び出しを追跡しつつ本物の実装を使う
テストのリファクタリング:
・テストが壊れやすい(実装変更で毎回失敗する)場合はテスト設計を見直す
・setup・teardown(beforeEach・afterEach)を使った共通処理の整理
・カスタムrender関数でProvider等をラップしてDRYなテストを書く