UIテスト(User Interface Test)とは、ユーザーが直接触れる画面の表示や操作(アプリケーションのユーザーインターフェース)が想定どおりに動作するかを検証するテストです。
ユーザーの「見る・入力する・クリックする・遷移する」といった動作を、開発者視点ではなくユーザー視点で正しく再現・確認することが目的です。
UIテストは「ユーザー体験を守る品質保証」の要です。
各レイヤーで「何を保証したいか」を明確にし、粒度に応じた適切なテスト手法を選ぶことが、効率的で堅牢なUI品質を実現します。
UIテストは目的とテスト対象の粒度により分類され、それぞれ役割が異なります。
テスト対象の粒度や目的に応じて、次のように分類されます。
| テスト種別 | 主な対象 | 概要 | 主なツール・技術 |
|---|---|---|---|
| ユニットテスト | 関数、内部ロジック | UI部品内の関数や状態変化の正しさを検証(表示の有無・出力の確認など) | Jest、Jasmine、Mocha |
| コンポーネントテスト | 単一のUIコンポーネント(DOM含む) | テンプレート + ロジックを含めた「UI部品」の動作を検証(表示・イベント処理など) | Testing Library、Vue Test Utils、TestBed(Angular)、Storybook + Jest |
| 結合テスト(Integration Test) | 複数コンポーネント間の連携、サービス連携など | 親子コンポーネント間のデータ連携、UIとバックエンドの接続、画面遷移を含む | Angular TestBed、Jest + Mock、Cypress(軽量E2Eとして) |
| スナップショットテスト | コンポーネントのHTML構造 | 出力されたDOM構造(HTML)に変化がないことを確認(構造のリグレッション検知) | JestのtoMatchSnapshot()、Vitest、Storyshots |
| ビジュアルリグレッションテスト | 見た目・レイアウト・色など | UIの視覚的な変化がないかをスクリーンショットレベルで比較検出 | Chromatic(Storybook)、Percy、Playwright Screenshotl、Applitools、BackstopJS |
| E2E(End-to-End)テスト | アプリ全体(ユーザーシナリオ、ワークフロー) | 実際のブラウザ上でユーザー操作を自動再現。UI + API + 画面遷移などを一括検証(フロントエンド+バックエンド) | Cypress、Playwright、Selenium |
開発段階や目的に応じて、どのテストをどのタイミングで実施するべきかを整理します。
| フェーズ | 適切なテスト | 目的 |
|---|---|---|
| 開発初期 | ユニット / コンポーネント | 小さなUI部品の正当性確認 |
| 機能結合 | 結合テスト | 部品間連携や副作用の確認 |
| リリース前 | スナップショット / ビジュアルリグレッション | 画面構造やデザイン崩れのチェック |
| QA / UAT | E2Eテスト | 本番同様のフローが動作するか確認 |
効率的かつ実用的なUIテストの設計・実行のための戦略と技法を紹介します。
-
テストピラミードの適用
- 単体・コンポーネントテスト(ベース層): 多数
- 統合テスト(中間層): 中程度
- E2Eテスト(頂点層): 少数、重要なフローのみ
-
テスティング・トロフィーの適用(モダンウェブ開発向け)
- 静的解析(ベース層): TypeScript, ESLint
- 単体テスト(小さい層): 15-20%
- 統合・コンポーネントテスト(最も重要な層): 50%
- E2Eテスト(頂点層): 10%、主要フローのみ
-
効果的なテスト選択
- ビジネスクリティカルな機能: E2Eを含む全レベル
- 一般的な機能: コンポーネント・統合テスト中心
- 視覚的デザイン: ビジュアルリグレッションテスト
- 基本的なUIロジック: ユニットテスト
-
安定性向上テクニック
- 堅牢なセレクター:
- データ属性 (data-testid="submit-button")
- アクセシビリティ属性 (役割、ラベル)
- 意味的要素 (セマンティクス)
- 待機戦略:
- 明示的な状態待機
- アニメーション完了検出
- 要素可視性確認
- テスト分離:
- テスト間の独立性確保
- 環境のリセット
- モックサーバーの活用
- 堅牢なセレクター:
-
コンポーネントテスト設計パターン
- Arrange-Act-Assert (AAA): 準備・実行・検証
- ページオブジェクトパターン: UI操作を抽象化
- コンポーネント境界テスト: 入力と出力に焦点
- 振る舞い駆動テスト: ユーザーの視点でのシナリオ
UIテストを安定的かつ有効に保つための設計・運用上の注意点をまとめます。
- ユーザー視点での検証を重視する(実装詳細への過剰依存を避ける)
- テストは重複せず階層的にカバーする(単体 → 結合 → 全体)
- E2Eだけに頼らず、各レベルのテストをバランスよく導入
- DOM構造の変化に依存しすぎる 脆弱(fragile) なテスト
➡️DOMの変更が頻繁に行われると、テストがすぐに壊れてしまうことがあります。
これを防ぐためには- テストの抽象化:
テストをDOMの具体的な構造に依存させず、より抽象的なレベルで記述する - データ駆動テスト:
テストデータを外部ファイルに分離し、DOMの変更に影響されにくくする - コンポーネントテスト:
個々のコンポーネントを独立してテストし、DOM全体の変更に対する影響を最小限に抑える - スナップショットテスト:
DOMのスナップショットを保存し、変更があった場合に比較する
- テストの抽象化:
- テストの実行速度を考慮する(遅いテストは開発効率を下げる)
- テストの信頼性(フラキーテスト対策)を確保する
- アクセシビリティの観点を含める(a11yのテスト自動化)
- レスポンシブデザインの検証も含める(複数画面サイズでのテスト)
Angular 開発におけるテストの種類と実践的なアプローチを示します。
| テスト種別 | Angularでの実践手段 |
|---|---|
| ユニットテスト | Jasmine + TestBed + モックサービス |
| コンポーネントテスト | ComponentFixture による DOM操作検証 |
| 結合テスト | 複数コンポーネント + DIサービスの連携確認 |
| E2Eテスト | Playwright or Cypress + ng serve で操作再現 |
React コンポーネント開発における主要なテスト手法とツールをまとめています。
| テスト種別 | Reactでの実践手段 |
|---|---|
| ユニットテスト | Jest、Vitest |
| コンポーネントテスト | React Testing Library、Enzyme(レガシー) |
| 結合テスト | React Testing Library + MSW(APIモック) |
| スナップショットテスト | Jest の toMatchSnapshot() |
| ビジュアルリグレッションテスト | Storybook + Chromatic、Percy |
| E2Eテスト | Cypress、Playwright |