<

タップ、ドラッグ、テキスト入力

多くのウィジェットは情報を表示するだけでなく、応答も行います ユーザーインタラクションに。これには、タップできるボタンが含まれます。 とTextFieldテキストを入力するためのものです。

これらのインタラクションをテストするには、それらをシミュレートする方法が必要です テスト環境で。この目的のために、WidgetTester図書館。

WidgetTesterテキストを入力するためのメソッドを提供します。 タップしてドラッグします。

  • enterText()
  • tap()
  • drag()

多くの場合、ユーザーの操作によってアプリの状態が更新されます。テストでは Flutter は、環境の状態が次の場合にウィジェットを自動的に再構築しません。 変化します。ユーザーをシミュレートした後にウィジェット ツリーが確実に再構築されるようにするには インタラクション、pump()またpumpAndSettle()によって提供されるメソッドWidgetTester。 このレシピでは次の手順を使用します。

  1. テストするウィジェットを作成します。
  2. テキストフィールドにテキストを入力します。
  3. ボタンをタップすると ToDo が追加されるようにしてください。
  4. スワイプして閉じると ToDo が削除されることを確認します。

1. テストするウィジェットを作成する

この例では、 3 つの機能をテストする基本的な ToDo アプリを作成します。

  1. にテキストを入力するTextField
  2. をタップするFloatingActionButtonをクリックして、ToDo リストにテキストを追加します。
  3. スワイプして閉じると、リストから項目が削除されます。

テストに集中し続けるために、 このレシピでは、ToDo アプリの構築方法に関する詳細なガイドは提供しません。 このアプリの構築方法について詳しくは、 関連するレシピを参照してください。

class TodoList extends StatefulWidget {
  const TodoList({super.key});

  @override
  State<TodoList> createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {
  static const _appTitle = 'Todo List';
  final todos = <String>[];
  final controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _appTitle,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(_appTitle),
        ),
        body: Column(
          children: [
            TextField(
              controller: controller,
            ),
            Expanded(
              child: ListView.builder(
                itemCount: todos.length,
                itemBuilder: (context, index) {
                  final todo = todos[index];

                  return Dismissible(
                    key: Key('$todo$index'),
                    onDismissed: (direction) => todos.removeAt(index),
                    background: Container(color: Colors.red),
                    child: ListTile(title: Text(todo)),
                  );
                },
              ),
            ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              todos.add(controller.text);
              controller.clear();
            });
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

2. テキストフィールドにテキストを入力します

Todo アプリが完成したので、テストの作成を開始します。 まずテキストを入力します。TextField

このタスクは次の方法で実行します。

  1. テスト環境でウィジェットを構築します。
  2. の使用enterText()からのメソッドWidgetTester
testWidgets('Add and remove a todo', (tester) async {
  // Build the widget
  await tester.pumpWidget(const TodoList());

  // Enter 'hi' into the TextField.
  await tester.enterText(find.byType(TextField), 'hi');
});

3. ボタンをタップすると Todo が追加されることを確認します

にテキストを入力した後、TextFieldをタップしてください。 のFloatingActionButton項目をリストに追加します。

これには次の 3 つのステップが含まれます。

  1. を使用して追加ボタンをタップしますtap()方法。
  2. 状態が変わった後、次のコマンドを使用してウィジェットを再構築します。pump()方法。
  3. リスト項目が画面に表示されていることを確認します。
testWidgets('Add and remove a todo', (tester) async {
  // Enter text code...

  // Tap the add button.
  await tester.tap(find.byType(FloatingActionButton));

  // Rebuild the widget after the state has changed.
  await tester.pump();

  // Expect to find the item on screen.
  expect(find.text('hi'), findsOneWidget);
});

4. スワイプして閉じると Todo が削除されることを確認する

最後に、ToDo に対してスワイプして閉じるアクションを実行していることを確認します。 item はリストから削除します。これには次の 3 つのステップが含まれます。

  1. 使用drag()スワイプして閉じるアクションを実行するメソッド。
  2. 使用pumpAndSettle()破棄されるまでウィジェット ツリーを継続的に再構築するメソッド アニメーションが完成しました。
  3. 項目が画面に表示されなくなったことを確認します。
testWidgets('Add and remove a todo', (tester) async {
  // Enter text and add the item...

  // Swipe the item to dismiss it.
  await tester.drag(find.byType(Dismissible), const Offset(500, 0));

  // Build the widget until the dismiss animation ends.
  await tester.pumpAndSettle();

  // Ensure that the item is no longer on screen.
  expect(find.text('hi'), findsNothing);
});

完全な例

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('Add and remove a todo', (tester) async {
    // Build the widget.
    await tester.pumpWidget(const TodoList());

    // Enter 'hi' into the TextField.
    await tester.enterText(find.byType(TextField), 'hi');

    // Tap the add button.
    await tester.tap(find.byType(FloatingActionButton));

    // Rebuild the widget with the new item.
    await tester.pump();

    // Expect to find the item on screen.
    expect(find.text('hi'), findsOneWidget);

    // Swipe the item to dismiss it.
    await tester.drag(find.byType(Dismissible), const Offset(500, 0));

    // Build the widget until the dismiss animation ends.
    await tester.pumpAndSettle();

    // Ensure that the item is no longer on screen.
    expect(find.text('hi'), findsNothing);
  });
}

class TodoList extends StatefulWidget {
  const TodoList({super.key});

  @override
  State<TodoList> createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {
  static const _appTitle = 'Todo List';
  final todos = <String>[];
  final controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _appTitle,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(_appTitle),
        ),
        body: Column(
          children: [
            TextField(
              controller: controller,
            ),
            Expanded(
              child: ListView.builder(
                itemCount: todos.length,
                itemBuilder: (context, index) {
                  final todo = todos[index];

                  return Dismissible(
                    key: Key('$todo$index'),
                    onDismissed: (direction) => todos.removeAt(index),
                    background: Container(color: Colors.red),
                    child: ListTile(title: Text(todo)),
                  );
                },
              ),
            ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              todos.add(controller.text);
              controller.clear();
            });
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}