集成测试介绍

Unit tests 和 Widget tests 在测试独立的类、函数或者组件时非常方便。然而,它们并不能够测试单独的模块形成的整体或者获取真实设备上应用运行状态。这些任务需要集成测试 (integration tests) 来处理。

Unit tests and widget tests are handy for testing individual classes, functions, or widgets. However, they generally don’t test how individual pieces work together as a whole, or capture the performance of an application running on a real device. These tasks are performed with integration tests.

集成测试由 SDK 直接提供支持,使用 integration_test 这个 package 实现。

Integration tests are written using the integration_test package, provided by the SDK.

在这个章节中,我们将会学习如何去测试一个计数器应用,包括如何设置集成测试、如何验证指定文本能否在应用内正常显示、如何模拟点击指定组件和如何运行集成测试。

In this recipe, learn how to test a counter app. It demonstrates how to setup integration tests, how to verify specific text is displayed by the app, how to tap specific widgets, and how to run integration tests.

本教程将包含以下步骤:

This recipe uses the following steps:

  1. 创建一个应用用于测试;

    Create an app to test.

  2. 添加 integration_test 依赖

    Add the integration_test dependency.

  3. 创建测试文件

    Create the test files.

  4. 编写集成测试

    Write the integration tests.

  5. 运行集成测试

    Run the integration test.

1. 创建一个应用用于测试

1. Create an app to test

首先,我们需要创建一个应用用于测试。在这个示例中,我们将会测试一个由 flutter create 命令创建的计数器应用。这个应用允许用户点击按钮增加计数。

First, create an app for testing. In this example, test the counter app produced by the flutter create command. This app allows a user to tap on a button to increase a counter.

此外,我们将会给 Text 组件和 FloatingActionButton 组件增加 ValueKey 属性。通过这个我们将可以在测试套件中标识特定组件并进行交互。

Furthermore, provide a ValueKey to the Text and FloatingActionButton widgets. This allows identifying and interacting with these specific widgets inside the test suite.

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Counter App',
      home: MyHomePage(title: 'Counter App Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              // Provide a Key to this specific Text widget. This allows
              // identifying the widget from inside the test suite,
              // and reading the text.
              key: const Key('counter'),
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        // Provide a Key to this button. This allows finding this
        // specific button inside the test suite, and tapping it.
        key: const Key('increment'),
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

2. 添加 integration_test 依赖

2. Add the integration_test dependency

接着,我们需要用到 integration_testflutter_driverflutter_test 这三个 package 来编写集成测试,把这三个依赖添加到应用pubspec.yaml 文件的 dev_dependencies 区域。

Next, use the integration_test, flutter_driver, and flutter_test packages to write integration tests. Add these dependencies to the dev_dependencies section of the app’s pubspec.yaml file, specifying the Flutter SDK as the location of the package.

dev_dependencies:
  integration_test:
    sdk: flutter
  flutter_test:
    sdk: flutter

3. 创建测试文件

3. Create the test files

创建一个名为 integration_test 的新文件夹,并在文件夹中创建一个空的 app_test.dart 文件:

Create a new directory, integration_test, with an empty app_test.dart file:

counter_app/
  lib/
    main.dart
  integration_test/
    app_test.dart

4. 编写集成测试文件

4. Write the integration test

现在我们可以来写测试文件了,步骤如下列三项:

Now you can write tests. This involves three steps:

  1. 初始化一个单例 IntegrationTestWidgetsFlutterBinding,这将用于在物理设备上执行测试;

    Initialize IntegrationTestWidgetsFlutterBinding, a singleton service that executes tests on a physical device.

  2. 使用 WidgetTester 类测试并与 widget 发生交互;

    Interact and tests widgets using the WidgetTester class.

  3. 测试重要的应用场景。

    Test the important scenarios.

import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import 'package:introduction/main.dart' as app;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('end-to-end test', () {
    testWidgets('tap on the floating action button, verify counter',
        (WidgetTester tester) async {
      app.main();
      await tester.pumpAndSettle();

      // Verify the counter starts at 0.
      expect(find.text('0'), findsOneWidget);

      // Finds the floating action button to tap on.
      final Finder fab = find.byTooltip('Increment');

      // Emulate a tap on the floating action button.
      await tester.tap(fab);

      // Trigger a frame.
      await tester.pumpAndSettle();

      // Verify the counter increments by 1.
      expect(find.text('1'), findsOneWidget);
    });
  });
}

5. 运行集成测试

5. Run the integration test

集成测试的运行情况会根据需要进行测试的平台不同而不尽相同,你可以针对移动平台或者 Web 平台进行测试。

The process of running the integration tests varies depending on the platform you are testing against. You can test against a mobile platform or the web.

5a. 移动平台

5a. Mobile

在 iOS 或 Android 平台进行真机测试的时候,首先需要连接设备并在工程的根目录运行下面的命令:

To test on a real iOS / Android device, first connect the device and run the following command from the root of the project:

flutter test integration_test/app_test.dart

或者你可以在指定目录下运行所有的集成测试:

Or, you can specify the directory to run all integration tests:

flutter test integration_test

这个命令可以在目标设备上运行应用并执行集成测试,更多相关信息,请参阅文档:集成测试 页面。

This command runs the app and integration tests on the target device. For more information, see the Integration testing page.

5b. Web 平台

5b. Web

在网页浏览器里开始进行集成测试,首先要下载 ChromeDriver

To get started testing in a web browser, Download ChromeDriver.

接下来,新建一个文件夹,命名为 test_driver,并包含一个新的文件,命名为 integration_test.dart

Next, create a new directory named test_driver containing a new file namedintegration_test.dart:

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();

运行 WebDriver,执行命令比如:

Launch WebDriver, for example:

chromedriver --port=4444

在工程的根目录下,运行如下命令:

From the root of the project, run the following command:

flutter drive \
  --driver=test_driver/integration_test.dart \
  --target=integration_test/app_test.dart \
  -d web-server