点击、拖动和输入文本
许多部件不仅显示信息,还响应用户交互。这包括可以点击的按钮,以及用于输入文本的 TextField
。
要测试这些交互,您需要一种在测试环境中模拟它们的方法。为此,请使用WidgetTester
库。
WidgetTester
提供用于输入文本、点击和拖动的方法。
在许多情况下,用户交互会更新应用程序的状态。在测试环境中,Flutter 不会在状态更改时自动重建小部件。为了确保在模拟用户交互后重建小部件树,请调用WidgetTester
提供的pump()
或pumpAndSettle()
方法。此示例使用以下步骤
- 创建要测试的小部件。
- 在文本字段中输入文本。
- 确保点击按钮会添加待办事项。
- 确保滑动以删除会移除待办事项。
1. 创建一个要测试的部件
#对于此示例,创建一个测试三个功能的基本待办事项应用程序
- 将文本输入
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
中输入文本。
通过以下方式完成此任务
- 在测试环境中构建小部件。
- 使用
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()
方法持续重建小部件树,直到删除动画完成。 - 确保该项目不再出现在屏幕上。
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。 查看源代码 或 报告问题.