flutter-testing について
Flutter 開発者向けのテスト戦略スキルで、カバレッジ、構成、独立性、命名の規約を示します。ユニット、ウィジェット、統合テストに使うゴールデンのバリエーション、状態マトリクス、インタラクション契約のパターンを解説します。
主な機能
- 01テストピラミッドとカバレッジの指針
- 02テストファイルの鏡像構成
- 03テスト独立性の規約
- 04ゴールデンのバリエーションテスト
- 05状態マトリクスとインタラクション契約
活用シーン
- 01デザインシステムのウィジェットの表示差分をテスト
- 02状態を持つウィジェットの全状態を確認
- 03再利用ウィジェットの操作規則を検証
- 04ユニット、ウィジェット、統合テストの実行
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dhruvanbhalara/ skills --skill flutter-testingインストール後、Claude Code で/flutter-testingを入力して読み込まれたか確認します。
詳細
テスト戦略
- テストピラミッド: ユニットテストとウィジェットテストを多めに、統合テストは少なめに。ユニットテストが最も速く、最も低コストです。
- ミラーテストルール: ロジックとウィジェットのカバレッジは 100%。テストのないコードはありません。
- ミラー構成: テストファイルは
lib/ディレクトリ構造を厳密にミラーし、_test.dartで終わる必要があります。 - カバレッジ目標:
domain層とbloc層のロジックカバレッジ 100% を目標とします。 - テストの独立性: 各テストは独立している必要があります。テスト間で可変状態を共有しないでください。
テストの種類の概要
| 種類 | 対象範囲 | 速度 | スキル |
|---|---|---|---|
| ユニット | 単一の関数/クラス | 高速 | dart-testing |
| ウィジェット | 単一の UI コンポーネント | 中速 | flutter-add-widget-test |
| 統合 | アプリ全体 / ユーザーフロー | 低速 | flutter-add-integration-test |
パターンベースのテスト
これら 3 つのパターンは、繰り返しになるテストのセットアップを削減し、すべての視覚的状態をカバーし、ウィジェットの動作を一貫したものに保ちます。これらはパッケージではなく、規約です。
ゴールデンバリアントテスト
ウィジェットが複数の視覚的状態(primary、disabled、hover、error)を持つ場合、Map<String, Widget Function()> を使った単一の構造化された group() ですべてのバリアントをテストします:
variantsマップを定義します。キーは状態名、値はウィジェットビルダーです。- 各バリアントは必ず分離してレンダリングする必要があります(バリアントごとに新しい
pumpWidget呼び出し)。 - 決定論的なゴールデンファイルの命名を使用します:
goldens/<component>.<variant>.png。 - 不安定なピクセル差分を避けるため、
tester.view.physicalSizeを介して一貫したsurfaceSizeを設定します。 - 使用すべき場合: デザインシステムのコンポーネント、異なるモードやタイプを持つウィジェット。
- 使用すべきでない場合: 統合テストやアニメーションフレームの検証。
状態マトリクステスト
すべてのステートフルウィジェットは、考えられるすべての UI 状態に対してテストする必要があります。状態マトリクスを使用して、セットアップと検証を分離します:
- ウィジェットがレンダリングできるすべての状態(
loading、error、data、empty)を持つstatesマップを定義します。 switch式を使って状態ごとに正しいレンダリングをアサートする、単一のverify(stateName)コールバックを記述します。- このパターンは「ハッピーパス」だけをテストしてしまうよくある間違いを防ぎます。
- 使用すべき場合: 複雑な状態機械を持つウィジェット(例: BLoC 駆動の画面)。
- 使用すべきでない場合: 検証ロジックが状態ごとに大きく異なる場合は、個別のテストを記述してください。
インタラクションコントラクトテスト
再利用可能なウィジェットには暗黙の動作ルールがあります。これらを明示的で再利用可能なコントラクトとして定義します:
- よく使うコントラクト用のヘルパー関数を
test/utils/に作成します:verifyTappable(tester, finder, mockCallback): タップでコールバックが正確に 1 回発火します。verifyDisabledNotTappable(tester, finder, mockCallback): 無効時にタップしてもコールバックが発火しません。verifyValidatesOnBlur(tester, finder): フォーカスが外れたときに検証がトリガーされます。
- 同じ動作を共有するすべてのウィジェットにコントラクトを一貫して適用します。
- 使用すべき場合: リファクタリングを経ても維持されるべき厳密に定義された動作ルールを持つウィジェット。
- 使用すべきでない場合: 単一のウィジェット固有の一度きりのロジック。
テストの命名と構造
- テストの命名: テストグループ名には文字列補間を使用します:
group('ClassName',ではなくgroup('$ClassName',。これにより一貫性が確保され、より良いツールサポートが可能になります。 - テストのグループ化:
group()を使用して、機能、クラス、状態ごとにテストを整理し、レポートをより明確にします。 - 説明的な名前: テスト名は、何をなぜテストするのかを明確に記述する必要があります。
よくあるテストエラー
A RenderFlex overflowed...: テストではウィジェットをExpandedでラップするか、寸法を制約しますVertical viewport was given unbounded height: テストではListViewを固定高さのSizedBoxでラップしますsetState called during build: 状態変更をフレーム後のコールバックに遅延させますNo MediaQuery widget ancestor: テストウィジェットを必ずMaterialAppでラップします
テストの実行(クイックリファレンス)
flutter test: すべてのユニットテストとウィジェットテストを実行しますflutter test test/path/to/file_test.dart: 特定のテストファイルを実行しますflutter test integration_test/: 統合テストを実行しますflutter test --coverage: カバレッジレポート付きで実行しますdart test: 純粋な Dart ユニットテスト
コメント
Markdown 対応