Testing Flutter apps翻译-点击,拖动和输入文本

栏目: 编程工具 · 发布时间: 5年前

内容简介:许多我们build的Widget不仅仅显示信息,也响应用户交互。包括可点击的按钮,在屏幕拖动控件,或者在文本框里输入文本。为了测试那些互动,我们需要一种在测试环境模拟它们的方法。为了这么做,我们需要使用这个

许多我们build的Widget不仅仅显示信息,也响应用户交互。包括可点击的按钮,在屏幕拖动控件,或者在文本框里输入文本。

为了测试那些互动,我们需要一种在测试环境模拟它们的方法。为了这么做,我们需要使用 flutter_test 类库的 WidgetTester 类。

这个 WidgetTester 提供了输入文本,点击,拖拽的方法。

在很多情况下,用户交互将会更新我们app的状态。在测试环境里,在状态改变后Flutter不会自动重新构建Widgets。为了确保我们的Widget树在我们模拟用户交互以后重新build,我们必须调用 WidgetTester 提供的 pump 或者 pumpAndSettle 方法。

步骤:

  1. 创建一个Widget用于测试
  2. 在输入框里输入文本
  3. 确保点击按钮会添加todo
  4. 确保滑动删除todo

1. 创建一个Widget用于测试

在这个例子里,我们将会创建一个基础的todo app。它将会有3个需要我们测试的主要功能:

TextField
FloatingActionButton

为了保持焦点在测试上,这个例子将不会提供详细的构建todo app的界面。如果想学习更多关于如何构建app,请查看以下相关文章:

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: 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: Icon(Icons.add),
        ),
      ),
    );
  }
}
复制代码

2. 在输入框里输入文本

现在我们有了一个todo app,我们可以开始写我们的测试了!在这个示例里,我们将会从输入文本到 TextField 开始。

我们可以这样完成任务:

  • 在测试环境build一个Widget
  • 使用 WidgetTester enterText 方法
testWidgets('Add and remove a todo', (WidgetTester tester) async {
  // Build the Widget
  await tester.pumpWidget(TodoList());

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

注意:这段代码基于上一段测试的代码。如果想学习Widget测试的核心概念,请查看下面的文章:

3. 确保点击按钮会添加todo

当我们在 TextField 里输入文本之后,我们希望点击 FloatingActionButton 会添加 item 到列表里。

这些步骤包括3步:

  1. 使用 tap 方法点击按钮。
  2. 状态改变后使用 pump 方法重新build Widget。
  3. 确保 item 出现在屏幕的列表里。
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);
});
复制代码

3. 滑动从列表中删除一个item

最后,我们要确保在滑动删除一条todo后可以从列表中删除它。这将包括以下3个步骤:

  1. 使用 drag 方法执行滑动删除操作。
  2. 使用 pumpAndSettle 方法不断的重新build我们的Widget树直到dismiss动画完成。
  3. 确保 item 从屏幕中消失。
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
  await tester.pumpAndSettle();

  // Ensure 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', (WidgetTester tester) async {
    // Build the Widget
    await tester.pumpWidget(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), Offset(500.0, 0.0));

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

    // Ensure the item is no longer on screen
    expect(find.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: 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: Icon(Icons.add),
        ),
      ),
    );
  }
}
复制代码

以上所述就是小编给大家介绍的《Testing Flutter apps翻译-点击,拖动和输入文本》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Purely Functional Data Structures

Purely Functional Data Structures

Chris Okasaki / Cambridge University Press / 1999-6-13 / USD 49.99

Most books on data structures assume an imperative language such as C or C++. However, data structures for these languages do not always translate well to functional languages such as Standard ML, Ha......一起来看看 《Purely Functional Data Structures》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具