null safety article
Contents
Tap, drag, and enter text
Many widgets not only display information, but also respond to user interaction. This includes buttons that can be tapped, and TextField
for entering text.
多くのウィジェットは、情報を表示するだけでなく、ユーザーの操作にも応答します。これには、タップできるボタンや、テキストを入力できるTextField
が含まれます。
To test these interactions, you need a way to simulate them in the test environment. For this purpose, use the WidgetTester
library.
これらの相互作用をテストするには、テスト環境でそれらをシミュレートする方法が必要です。この目的のために、WidgetTester
ライブラリを使用してください 。
The WidgetTester
provides methods for entering text, tapping, and dragging.
WidgetTester
は、テキストを入力する方法、タップ、およびドラッグするためのメソッドを提供します
In many cases, user interactions update the state of the app.
多くの場合、ユーザーの操作によってアプリの状態(state)が更新されます。
In the test environment, Flutter doesn’t automatically rebuild widgets when the state changes.
テスト環境では、状態が変化してもFlutterはウィジェットを自動的に再構築(リビルド)しません。
To ensure that the widget tree is rebuilt after simulating a user interaction, call the pump()
or pumpAndSettle()
methods provided by the WidgetTester
.
ウィジェットツリーがユーザーの相互作用をシミュレートした後に再構築(リビルド)されるようにするには、WidgetTesterによって提供されるpump()またはpumpAndSettle()メソッドを呼び出します。
This recipe uses the following steps:
このレシピは次のステップを使用します。
- Create a widget to test.
- Enter text in the text field.
- Ensure tapping a button adds the todo.
- Ensure swipe-to-dismiss removes the todo.
1.テスト対象ウィジェットを定義します。
2.テキストフィールドに文字列を入力します。
3.ボタンを押すとtodoを追加するようにします。
4.swipe-to-dismissでtodoを消去できるようにします。
1. Create a widget to test
For this example, create a basic todo app that tests three features:
この例では、3つの機能をテストする基本的なTODOアプリを作成します。
TextField
.テキストフィールドに文字列を入力する。
2.Tapping a FloatingActionButton
to add the text to a list of todos.
FloatingActionButtonを押すと入力した文字列をtodoリストに追加する。
3.Swiping-to-dismiss to remove the item from the list.
swipe-to-dismissでリストからtodoを消去できるようにします。
To keep the focus on testing, this recipe won’t provide a detailed guide on how to build the todo app. To learn more about how this app is built, see the relevant recipes:
テストに焦点を当てるために、このレシピはTODOアプリの構築方法に関する詳細なガイドを提供しません。このアプリがどのように構築されているかについて詳しくは、関連するレシピを参照してください。
class TodoList extends StatefulWidget { const TodoList({Key? key}) : super(key: key); @override _TodoListState 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: (BuildContext context, int index) { final todo = todos[index]; return Dismissible( key: Key('$todo$index'), onDismissed: (direction) => todos.removeAt(index), child: ListTile(title: Text(todo)), background: Container(color: Colors.red), ); }, ), ), ], ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { todos.add(controller.text); controller.clear(); }); }, child: const Icon(Icons.add), ), ), ); } }
2. Enter text in the text field
Now that you have a todo app, begin writing the test. Start by entering text into the TextField
.
テスト対象のtodoアプリができましたので、テストを書いていきましょう。まずテキストフィールドに文字列を入力します。
Accomplish this task by:
1.Building the widget in the test environment.
テスト環境にウィジェットを構築します。
2.Using the enterText()
method from the WidgetTester
.
WidgetTesterクラスのenterText()メソッドを使います。
testWidgets('Add and remove a todo', (WidgetTester tester) async {
// Build the widget
//ウィジェットを構築します。
await tester.pumpWidget(TodoList());
// Enter 'hi' into the TextField.
//テキストフィールドに'hi'と入力します。
await tester.enterText(find.byType(TextField), 'hi');
});
Note: This recipe builds upon previous widget testing recipes. To learn the core concepts of widget testing, see the following recipes:
注:このレシピは以前のウィジェットテストレシピの知識を前提としています。ウィジェットテストのコア概念を学ぶには、次のレシピを参照してください。
After entering text into the TextField
, ensure that tapping the FloatingActionButton
adds the item to the list.
テキストフィールドに入力したら、FABをタップしてリストにアイテムを追加します。
This involves three steps:
次の三つのステップでやっていきます。
1.Tap the add button using the tap()
method.
tap()メソッドを使ってadd buttonをタップします。
2.Rebuild the widget after the state has changed using the pump()
method.
pump()メソッドを使って、状態(state)が変化した後にウィジェットをリビルドします。
3.Ensure that the list item appears on screen.
リスト項目が画面に表示されていることを確認します。
testWidgets('Add and remove a todo', (WidgetTester 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. Ensure swipe-to-dismiss removes the todo
Finally, ensure that performing a swipe-to-dismiss action on the todo item removes it from the list. This involves three steps:
最後にtodoアイテムにswipe-to-dismissアクションを行ってリストからtodoアイテムを削除します。
次の三つのステップでやっていきます。
1.Use the drag()
method to perform a swipe-to-dismiss action.
swipe-to-dismissアクションを行うためにdrag()メソッドを使います。
2.Use the pumpAndSettle()
method to continually rebuild the widget tree until the dismiss animation is complete.
dismissアニメーションが完了するまでウィジェットをリビルドし続けるため、pumpAndSettle()メソッドを使います。
3.Ensure that the item no longer appears on screen.
画面からアイテムが削除されたことを確認します。
testWidgets('Add and remove a todo', (WidgetTester tester) async {
// Enter text and add the item...
// Swipe the item to dismiss it.
//アイテムを削除するためスワイプします。
await tester.drag(find.byType(Dismissible), Offset(500.0, 0.0));
// Build the widget until the dismiss animation ends.
//dismissアニメーションが完了するまでウィジェットをリビルドします。
await tester.pumpAndSettle();
// Ensure that the item is no longer on screen.
//画面にアイテムが無いことを確認します。
expect(find.text('hi'), findsNothing);
});
Complete example
import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('Add and remove a todo', (WidgetTester 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, 0.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({Key? key}) : super(key: key); @override _TodoListState 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: (BuildContext context, int index) { final todo = todos[index]; return Dismissible( key: Key('$todo$index'), onDismissed: (direction) => todos.removeAt(index), child: ListTile(title: Text(todo)), background: Container(color: Colors.red), ); }, ), ), ], ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { todos.add(controller.text); controller.clear(); }); }, child: const Icon(Icons.add), ), ), ); } }
参考