返回介绍

Tapping, dragging and entering text

发布于 2019-12-09 21:31:29 字数 14830 浏览 978 评论 0 收藏 0

Many of the Widgets we build not only display information, but also respond to user interactionhttps://flutter.axuer.com/docs/cookbook/testing/widget/. This includes buttons that users can tap on, dragging items across the screen, or entering text into a TextFieldhttps://flutter.axuer.com/docs/cookbook/testing/widget/.

In order to test these interactions, we need a way to simulate them in the test environmenthttps://flutter.axuer.com/docs/cookbook/testing/widget/. To do so, we can use the WidgetTester class provided by the flutter_test libraryhttps://flutter.axuer.com/docs/cookbook/testing/widget/.

The WidgetTester provides methods for entering text, tapping, and dragginghttps://flutter.axuer.com/docs/cookbook/testing/widget/.

In many cases, user interactions will update the state of our apphttps://flutter.axuer.com/docs/cookbook/testing/widget/. In the test environment, Flutter will not automatically rebuild widgets when the state changeshttps://flutter.axuer.com/docs/cookbook/testing/widget/. To ensure our Widget tree is rebuilt after we simulate a user interaction, we must call the pump or pumpAndSettle methods provided by the WidgetTesterhttps://flutter.axuer.com/docs/cookbook/testing/widget/.

Directions

  1. Create a Widget to test
  2. Enter text in the text field
  3. Ensure tapping a button adds the todo
  4. Ensure swipe-to-dismiss removes the todo

1https://flutter.axuer.com/docs/cookbook/testing/widget/. Create a Widget to test

For this example, we’ll create a basic todo apphttps://flutter.axuer.com/docs/cookbook/testing/widget/. It will have three main features that we’ll want to test:

  1. Enter text into a TextField
  2. Tapping a FloatingActionButton adds the text to a list of todos
  3. Swipe-to-dismiss removes the item from the list

To keep the focus on testing, this recipe will not provide a detailed guide on how to build the todo apphttps://flutter.axuer.com/docs/cookbook/testing/widget/. To learn more about how this app is built, please see the relevant recipes:

class TodoList extends StatefulWidget {
  @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: Text(_appTitle),
        ),
        body: Column(
          children: [
            TextField(
              controller: controller,
            ),
            Expanded(
              child: ListViewhttps://flutter.axuer.com/docs/cookbook/testing/widget/.builder(
                itemCount: todoshttps://flutter.axuer.com/docs/cookbook/testing/widget/.length,
                itemBuilder: (BuildContext context, int index) {
                  final todo = todos[index];

                  return Dismissible(
                    key: Key('$todo$index'),
                    onDismissed: (direction) => todoshttps://flutter.axuer.com/docs/cookbook/testing/widget/.removeAt(index),
                    child: ListTile(title: Text(todo)),
                    background: Container(color: Colorshttps://flutter.axuer.com/docs/cookbook/testing/widget/.red),
                  );
                },
              ),
            ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              todoshttps://flutter.axuer.com/docs/cookbook/testing/widget/.add(controllerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.text);
              controllerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.clear();
            });
          },
          child: Icon(Iconshttps://flutter.axuer.com/docs/cookbook/testing/widget/.add),
        ),
      ),
    );
  }
}

2https://flutter.axuer.com/docs/cookbook/testing/widget/. Enter text in the text field

Now that we have a todo app, we can begin writing our test! In this case, we’ll start by entering text into the TextFieldhttps://flutter.axuer.com/docs/cookbook/testing/widget/.

We can accomplish this task by:

  1. Building the Widget in the Test Environment
  2. Using the enterText method from the WidgetTester
testWidgets('Add and remove a todo', (WidgetTester tester) async {
  // Build the Widget
  await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.pumpWidget(TodoList());

  // Enter 'hi' into the TextField
  await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.enterText(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.byType(TextField), 'hi');
});

Note: This recipe builds upon previous Widget testing recipeshttps://flutter.axuer.com/docs/cookbook/testing/widget/. To learn the core concepts of Widget testing, see the following recipes:

3https://flutter.axuer.com/docs/cookbook/testing/widget/. Ensure tapping a button adds the todo

After we’ve entered text into the TextField, we’ll want to ensure that tapping the FloatingActionButton adds the item to the listhttps://flutter.axuer.com/docs/cookbook/testing/widget/.

This will involve three steps:

  1. Tap the add button using the tap method
  2. Rebuild the Widget after the state has changed using the pump method
  3. Ensure the list item appears on screen
testWidgets('Add and remove a todo', (WidgetTester tester) async {
  // Enter text codehttps://flutter.axuer.com/docs/cookbook/testing/widget/.https://flutter.axuer.com/docs/cookbook/testing/widget/.https://flutter.axuer.com/docs/cookbook/testing/widget/.

  // Tap the add button
  await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.tap(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.byType(FloatingActionButton));

  // Rebuild the Widget after the state has changed
  await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.pump();

  // Expect to find the item on screen
  expect(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.text('hi'), findsOneWidget);
});

4https://flutter.axuer.com/docs/cookbook/testing/widget/. Ensure swipe-to-dismiss removes the todo

Finally, we can ensure that performing a swipe-to-dismiss action on the todo item will remove it from the listhttps://flutter.axuer.com/docs/cookbook/testing/widget/. This will involve three steps:

  1. Use the drag method to perform a swipe-to-dismiss actionhttps://flutter.axuer.com/docs/cookbook/testing/widget/.
  2. Use the pumpAndSettle method to continually rebuild our Widget tree until the dismiss animation is completehttps://flutter.axuer.com/docs/cookbook/testing/widget/.
  3. Ensure the item no longer appears on screenhttps://flutter.axuer.com/docs/cookbook/testing/widget/.
testWidgets('Add and remove a todo', (WidgetTester tester) async {
  // Enter text and add the itemhttps://flutter.axuer.com/docs/cookbook/testing/widget/.https://flutter.axuer.com/docs/cookbook/testing/widget/.https://flutter.axuer.com/docs/cookbook/testing/widget/.

  // Swipe the item to dismiss it
  await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.drag(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.byType(Dismissible), Offset(500https://flutter.axuer.com/docs/cookbook/testing/widget/.0, 0https://flutter.axuer.com/docs/cookbook/testing/widget/.0));

  // Build the Widget until the dismiss animation ends
  await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.pumpAndSettle();

  // Ensure the item is no longer on screen
  expect(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.text('hi'), findsNothing);
});

Complete example

Once we’ve completed these steps, we should have a working app with a test to ensure it works correctly!

import 'package:flutter/materialhttps://flutter.axuer.com/docs/cookbook/testing/widget/.dart';
import 'package:flutter_test/flutter_testhttps://flutter.axuer.com/docs/cookbook/testing/widget/.dart';

void main() {
  testWidgets('Add and remove a todo', (WidgetTester tester) async {
    // Build the Widget
    await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.pumpWidget(TodoList());

    // Enter 'hi' into the TextField
    await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.enterText(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.byType(TextField), 'hi');

    // Tap the add button
    await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.tap(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.byType(FloatingActionButton));

    // Rebuild the Widget with the new item
    await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.pump();

    // Expect to find the item on screen
    expect(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.text('hi'), findsOneWidget);

    // Swipe the item to dismiss it
    await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.drag(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.byType(Dismissible), Offset(500https://flutter.axuer.com/docs/cookbook/testing/widget/.0, 0https://flutter.axuer.com/docs/cookbook/testing/widget/.0));

    // Build the Widget until the dismiss animation ends
    await testerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.pumpAndSettle();

    // Ensure the item is no longer on screen
    expect(findhttps://flutter.axuer.com/docs/cookbook/testing/widget/.text('hi'), findsNothing);
  });
}

class TodoList extends StatefulWidget {
  @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: Text(_appTitle),
        ),
        body: Column(
          children: [
            TextField(
              controller: controller,
            ),
            Expanded(
              child: ListViewhttps://flutter.axuer.com/docs/cookbook/testing/widget/.builder(
                itemCount: todoshttps://flutter.axuer.com/docs/cookbook/testing/widget/.length,
                itemBuilder: (BuildContext context, int index) {
                  final todo = todos[index];

                  return Dismissible(
                    key: Key('$todo$index'),
                    onDismissed: (direction) => todoshttps://flutter.axuer.com/docs/cookbook/testing/widget/.removeAt(index),
                    child: ListTile(title: Text(todo)),
                    background: Container(color: Colorshttps://flutter.axuer.com/docs/cookbook/testing/widget/.red),
                  );
                },
              ),
            ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              todoshttps://flutter.axuer.com/docs/cookbook/testing/widget/.add(controllerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.text);
              controllerhttps://flutter.axuer.com/docs/cookbook/testing/widget/.clear();
            });
          },
          child: Icon(Iconshttps://flutter.axuer.com/docs/cookbook/testing/widget/.add),
        ),
      ),
    );
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文