🔍
Widgetテストによって発見できること
Widgetテストの意義
Widgetテストを行うことで、アプリのUIやロジックの不具合を早期に発見できる。特に、UIコンポーネントの動作やユーザー操作に関連する問題を検出するのに役立つ。この記事ではWidgetテストによって発見できる具体的な問題を挙げて扱う。
Widgetテストによって発見できる問題は大まかにいうと
- ユーザーの操作に関連する動作不良(タップ、入力、スクロールなど)。
- UI表示や非表示の問題。
具体例
1. ユーザー操作に伴うUIの動作不具合
- ボタンが正しく反応しない。
- ユーザーの操作(タップ、スワイプなど)に対して期待通りの画面変更が行われない。
問題: ボタンを押しても次の画面に遷移しない。
testWidgets('ボタンを押すと正しく画面遷移が行われる', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
// ボタンをタップ
await tester.tap(find.text('次へ'));
await tester.pumpAndSettle();
// 次の画面が表示されていることを確認
expect(find.text('新しい画面の文字'), findsOneWidget);
});
2. UIコンポーネントの表示・非表示の問題
- 必要なWidgetが表示されていない、または表示されるべきでないWidgetが表示されている。
- 状態の変化に応じたWidgetの切り替えが正しく行われていない。
testWidgets('アプリ起動時のローディング中にIndicatorが表示され、ローディングが終わると消える', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
// ローディング中はIndicatorが表示される
expect(find.byType(CircularProgressIndicator), findsOneWidget);
// データ取得後、Indicatorが消える
await tester.pumpAndSettle();
expect(find.byType(CircularProgressIndicator), findsNothing);
});
3. ユーザー入力のバリデーションエラー
- 不正な入力をした際に適切なエラーメッセージが表示されない。
- 入力データが正しく処理されない。
testWidgets('空の入力フィールドでエラーメッセージが表示される', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
// フォームの送信ボタンをタップ
await tester.tap(find.text('送信'));
await tester.pump();
// エラーメッセージが表示されることを確認
expect(find.text('このフィールドは必須です'), findsOneWidget);
});
4. リストやスクロールの動作不具合
- リストが正しくレンダリングされない。
- スクロールが正しく動作しない。
testWidgets('リストの全ての項目が表示される', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
// リストが表示されていることを確認
expect(find.byType(ListTile), findsNWidgets(10));
// スクロールして新しい項目を確認
await tester.drag(find.byType(ListView), const Offset(0, -300));
await tester.pump();
expect(find.text('アイテム11'), findsOneWidget);
});
5. 画面遷移の不具合
- 正しい条件で画面遷移が行われない。
- 遷移先の画面で状態が引き継がれない。
testWidgets('選択した項目が詳細画面に渡される', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
// 項目をタップ
await tester.tap(find.text('アイテム1'));
await tester.pumpAndSettle();
// 詳細画面で正しいデータが表示されていることを確認
expect(find.text('詳細: アイテム1'), findsOneWidget);
});
6. 条件分岐の確認
- 条件に応じたUIが正しく表示されない。
- 状態管理が正しく行われていない。
testWidgets('ログイン状態に応じて画面が切り替わる', (WidgetTester tester) async {
await tester.pumpWidget(MyApp(isLoggedIn: true));
// ログイン状態ではダッシュボードが表示される
expect(find.text('ダッシュボード'), findsOneWidget);
await tester.pumpWidget(MyApp(isLoggedIn: false));
// 非ログイン状態ではログイン画面が表示される
expect(find.text('ログイン画面'), findsOneWidget);
});
7. UI表示の不整合
- 日付や通貨のデータが正しい形式で表示されない。
- 表示が不完全、欠落している。
testWidgets('データがnullの場合、デフォルト値が表示される', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: MyWidget(
data: {
'name': null, // 名前がnull
},
),
),
);
// デフォルト値が表示されることを確認
expect(find.text('Guest'), findsOneWidget);
});
8. オリジナルのWidgetの再利用による問題
- カスタムWidgetの動作が期待通りでない。
- 他の画面で再利用した場合に不具合が発生する。
testWidgets('カスタムボタンが期待通りに動作する', (WidgetTester tester) async {
// モック関数を定義
bool isPressed = false;
void onPressedMock() {
isPressed = true;
}
// テスト用ウィジェットを作成
await tester.pumpWidget(
MaterialApp(
home: CustomButton(
label: 'クリック',
onPressed: onPressedMock,
),
),
);
// ボタンのラベルを確認
expect(find.text('クリック'), findsOneWidget);
// ボタンをタップして動作を確認
await tester.tap(find.text('クリック'));
await tester.pump(); // 状態更新を反映
// ボタンの動作が正しいか確認
expect(isPressed, true); // モック関数が呼ばれたことを確認
});
まとめ
Widgetテストを行うことで、アプリのUIやユーザー操作に関する不具合を早期に発見・修正でき、アプリの品質向上と開発効率の向上につながる。
Discussion