點擊、拖曳和輸入文字
許多 Widget 不僅顯示資訊,還會回應使用者互動。這包括可點擊的按鈕,以及用於輸入文字的 TextField
。
若要測試這些互動,您需要在測試環境中模擬它們。為此,請使用 WidgetTester
函式庫。
WidgetTester
提供輸入文字、點擊和拖曳的方法。
在許多情況下,使用者互動會更新應用程式的狀態。在測試環境中,當狀態變更時,Flutter 不會自動重建 Widget。為了確保在模擬使用者互動後重建 Widget 樹狀結構,請呼叫 WidgetTester
提供的 pump()
或 pumpAndSettle()
方法。此食譜使用以下步驟
- 建立一個要測試的 Widget。
- 在文字欄位中輸入文字。
- 確保點擊按鈕會新增待辦事項。
- 確保滑動移除會刪除待辦事項。
1. 建立一個要測試的 Widget
#在此範例中,建立一個基本的待辦事項應用程式,測試三個功能
- 在
TextField
中輸入文字。 - 點擊
FloatingActionButton
將文字新增至待辦事項清單。 - 滑動移除以從清單中移除項目。
為了將重點放在測試上,此食譜不會提供如何建立待辦事項應用程式的詳細指南。若要瞭解如何建立此應用程式的更多資訊,請參閱相關的食譜
dart
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. 在文字欄位中輸入文字
#現在您已經有了待辦事項應用程式,開始撰寫測試。首先在 TextField
中輸入文字。
透過以下方式完成此任務
- 在測試環境中建立 Widget。
- 使用
WidgetTester
中的enterText()
方法。
dart
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. 確保點擊按鈕會新增待辦事項
#在 TextField
中輸入文字後,確保點擊 FloatingActionButton
會將項目新增至清單。
這包含三個步驟
dart
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. 確保滑動移除會刪除待辦事項
#最後,確保對待辦事項項目執行滑動移除動作會將其從清單中移除。這包含三個步驟
- 使用
drag()
方法執行滑動移除動作。 - 使用
pumpAndSettle()
方法,持續重建 Widget 樹狀結構,直到移除動畫完成。 - 確保項目不再出現在螢幕上。
dart
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);
});
完整範例
#dart
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),
),
),
);
}
}
除非另有說明,否則本網站上的文件反映 Flutter 的最新穩定版本。頁面最後更新於 2024-04-04。 檢視原始碼 或 回報問題。