なぜテストを書くべきか|テストの価値
「テストを書く時間がない」「動くコードにテストは不要」という声をよく聞きますが、中長期的には「テストがないコードの維持コスト」の方が圧倒的に高くつきます。テストが整備されていれば、リファクタリング・新機能追加時の既存機能への影響を素早く確認でき、自信を持ってコードを変更できます。
テストを書くメリット:
・バグの早期発見(本番環境でバグを発見するより開発時の方が修正コストが低い)
・仕様のドキュメントとして機能(テストコードを読むと動作仕様が理解できる)
・リファクタリングへの自信(テストがあれば安心して改善できる)
・チーム開発での品質担保(CIでテストが通ることを合流の条件にできる)
JestとVitestの選び方
JavaScriptのテストフレームワークとして最も広く使われているJestと、Viteを使ったモダンなプロジェクトで急速に普及しているVitestの使い分けを解説します。
Vitest(2025年推奨):
・Viteと統合されているため設定がシンプル
・実行速度がJestより高速(特に大規模テスト)
・JestとほぼAPI互換のため移行が容易
・Next.js・Vite・SvelteKit等のモダンプロジェクトに最適
Jest(老舗・安定):
・最も広く使われているためリソースが豊富
・Create React App等の古い構成との互換性が高い
・node_modules系のテストに強い
新規プロジェクトにはVitestを推奨します。JestからVitestへの移行は、設定ファイルの変更と一部のAPIの差分対応で可能です。
ユニットテストの書き方
関数・ユーティリティのユニットテストの基本的な書き方を解説します。
テストの基本構造(AAAパターン):
Arrange(準備)→ Act(実行)→ Assert(検証)の3ステップが基本です。
よく使う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の推奨):
getByRole → getByLabelText → getByPlaceholderText → getByText → getByTestId の順で使いましょう。getByTestIdはアクセシビリティを考慮したクエリが使えない場合の最終手段です。
テストの品質を高めるための実践テクニック
テストを書く上で知っておくべき実践的なテクニックを紹介します。
モックの活用:
・外部APIのモック(msw/mswjs):APIリクエストをインターセプトしてモックレスポンスを返す
・モジュールのモック(vi.mock・jest.mock):依存モジュールを置き換える
・spyOn:関数の呼び出しを追跡しつつ本物の実装を使う
テストのリファクタリング:
・テストが壊れやすい(実装変更で毎回失敗する)場合はテスト設計を見直す
・setup・teardown(beforeEach・afterEach)を使った共通処理の整理
・カスタムrender関数でProvider等をラップしてDRYなテストを書く