跳转至正文

通过集成测试检查应用的功能

学习如何编写集成测试

介绍

#

本指南说明如何为 Flutter 应用运行集成测试。你将学习如何:

  • Set up integration tests.

  • Verify if an app displays specific text.

  • Tap specific widgets.

  • Run integration tests.

  • 设置集成测试。

  • 验证应用是否显示特定文本。

  • 点击特定 widget。

  • 运行集成测试。

本指南引用 Flutter 自带的 counter_app 项目以及 Flutter integration_test package。integration_test package 可以:

  • Use the flutter drive command to run tests on a physical device or emulator.

  • Run on Firebase Test Lab, to automate testing on a variety of devices.

  • Use flutter_test APIs to write tests in a style similar to widget tests.

  • 使用 flutter drive 命令在真机或模拟器上运行测试。

  • Firebase Test Lab 上运行,在多种设备上自动化测试。

  • 使用 flutter_test API,以类似 widget 测试的风格编写测试。

创建待测新应用

#

集成测试需要待测应用。本示例使用运行 flutter create 时 Flutter 生成的内置计数器应用。计数器应用允许用户点击按钮增加计数。

  1. 要在终端中创建内置 Flutter 应用实例,请运行:

    flutter create counter_app
    
  2. 进入 counter_app 目录。

  3. 在你偏好的 IDE 中打开 lib/main.dart

  4. floatingActionButton() widget 添加 key 参数,使用字符串值为 incrementKey 类实例。

    dart
     floatingActionButton: FloatingActionButton(
       key: const ValueKey('increment'),
       onPressed: _incrementCounter,
       tooltip: 'Increment',
       child: const Icon(Icons.add),
     ),
    
  5. 保存 lib/main.dart 文件。

完成上述修改后,lib/main.dart 应类似以下代码。

lib/main.dart
dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.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({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> 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',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      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),
      ),
    );
  }
}

添加 integration_test 依赖

#

需要为新建应用添加测试 package。

要使用 sdk: flutterintegration_testflutter_test package 添加为 dev_dependencies,请运行:

flutter pub add "dev:integration_test:{sdk: flutter}"

输出:

Building flutter tool...
Resolving dependencies...
Got dependencies.
Resolving dependencies...
+ file 7.0.0
+ flutter_driver 0.0.0 from sdk flutter
+ fuchsia_remote_debug_protocol 0.0.0 from sdk flutter
+ integration_test 0.0.0 from sdk flutter
...
  test_api 0.6.1 (0.7.1 available)
  vm_service 13.0.0 (14.2.1 available)
+ webdriver 3.0.3
Changed 8 dependencies!
7 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

更新后的 pubspec.yaml 文件:

pubspec.yaml
yaml
# ...
dev_dependencies:
  # ... added dependencies
  flutter_test:
    sdk: flutter
  flutter_lints: ^6.0.0
  integration_test:
    sdk: flutter
# ...

创建集成测试文件

#

集成测试位于 Flutter 项目内的独立目录中。

  1. Create a new directory named integration_test.

  2. Add empty file named app_test.dart in that directory.

  3. 新建名为 integration_test 的目录。

  4. 在该目录中添加名为 app_test.dart 的空文件。

最终目录树应类似:

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

编写集成测试

#

集成测试文件是由依赖 integration_testflutter_test 以及应用 Dart 文件的 Dart 代码文件组成。

  1. 在你偏好的 IDE 中打开 integration_test/app_test.dart

  2. 将以下代码复制并粘贴到 integration_test/app_test.dart。最后一个 import 应指向 counter_appmain.dart。(此 import 指向名为 introduction 的示例应用。)

    integration_test/counter_test.dart
    dart
    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:how_to/main.dart';
    import 'package:integration_test/integration_test.dart';
    
    void main() {
      IntegrationTestWidgetsFlutterBinding.ensureInitialized();
    
      group('end-to-end test', () {
        testWidgets('tap on the floating action button, verify counter', (
          tester,
        ) async {
          // Load app widget.
          await tester.pumpWidget(const MyApp());
    
          // Verify the counter starts at 0.
          expect(find.text('0'), findsOneWidget);
    
          // Finds the floating action button to tap on.
          final fab = find.byKey(const ValueKey('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);
        });
      });
    }
    

本示例分三步:

  1. Initialize IntegrationTestWidgetsFlutterBinding. This singleton service executes tests on a physical device.

  2. 初始化 IntegrationTestWidgetsFlutterBinding。该单例服务在物理设备上执行测试。

  3. Interact and test widgets using the WidgetTester class.

  4. 使用 WidgetTester 类与 widget 交互并测试。

  5. Test the important scenarios.

  6. 测试重要场景。

运行集成测试

#

运行的集成测试因测试平台而异。

  • To test a desktop platform, use the command line or a CI system.

  • To test a mobile platform, use the command line or Firebase Test Lab.

  • To test in a web browser, use the command line.

  • 在桌面平台上测试,请使用命令行或 CI 系统。

  • 在移动平台上测试,请使用命令行或 Firebase Test Lab。

  • 在 Web 浏览器中测试,请使用命令行。


在桌面平台上测试

#
Expand if you test Linux apps using a CI system / 若使用 CI 系统测试 Linux 应用请展开

To test a Linux app, your CI system must invoke an X server first. In the GitHub Action, GitLab Runner, or similar configuration file, set the integration test to work with the xvfb-run tool.

Doing this invokes an X Window system into which Flutter can launch and test your Linux app.

测试 Linux 应用时,CI 系统须先启动 X server。在 GitHub Action、GitLab Runner 或类似配置文件中,将集成测试配置为与 xvfb-run 工具配合使用。这样会启动 X Window 系统,Flutter 可在其中启动并测试 Linux 应用。

以 GitHub Actions 为例,jobs.setup.steps 应包含类似下面的步骤:

Example workflow

#

目录结构

#
yaml
      - name: Run Integration Tests
        uses: username/xvfb-action@v1.1.2
        with:
          run: flutter test integration_test -d linux -r github

This starts the integration test within an X Window.

这样会先在 X Window 中启动集成测试。若未如此配置集成测试,Flutter 会返回错误。

Building Linux application...
Error waiting for a debug connection: The log reader stopped unexpectedly, or never started.

在 macOS、Windows 或 Linux 平台上测试,请完成以下任务。

  1. 在项目根目录运行:

    flutter test integration_test/app_test.dart
    
  2. 若提示选择测试平台,请选择桌面平台。输入 1 选择桌面平台。

根据平台,命令结果应类似以下输出。

PS C:\path\to\counter_app> flutter test .\integration_test\app_test.dart
Resolving dependencies...
Downloading packages...
  flutter_lints 3.0.2 (4.0.0 available)
  leak_tracker 10.0.4 (10.0.5 available)
  leak_tracker_flutter_testing 3.0.3 (3.0.5 available)
  lints 3.0.0 (4.0.0 available)
  material_color_utilities 0.8.0 (0.11.1 available)
  meta 1.12.0 (1.15.0 available)
  test_api 0.7.0 (0.7.1 available)
  vm_service 14.2.1 (14.2.2 available)
Got dependencies!
8 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

Connected devices:

Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22631.3593]
Chrome (web)      • chrome  • web-javascript • Google Chrome 124.0.6367.207
Edge (web)        • edge    • web-javascript • Microsoft Edge 124.0.2478.97

[1]: Windows (windows)
[2]: Chrome (chrome)
[3]: Edge (edge)

Please choose one (or "q" to quit): 1

00:00 +0: loading C:/path/to/counter_app/integration_test/app_test.dart               B
00:29 +0: loading C:/path/to/counter_app/counter_app/integration_test/app_test.dart   29.1s
√ Built build\windows\x64\runner\Debug\counter_app.exe
00:31 +1: All tests passed!
flutter test integration_test
Resolving dependencies...
Downloading packages...
  flutter_lints 3.0.2 (4.0.0 available)
> leak_tracker 10.0.4 (was 10.0.0) (10.0.5 available)
> leak_tracker_flutter_testing 3.0.3 (was 2.0.1) (3.0.5 available)
> leak_tracker_testing 3.0.1 (was 2.0.1)
  lints 3.0.0 (4.0.0 available)
  material_color_utilities 0.8.0 (0.11.1 available)
> meta 1.12.0 (was 1.11.0) (1.15.0 available)
> test_api 0.7.0 (was 0.6.1) (0.7.1 available)
> vm_service 14.2.1 (was 13.0.0) (14.2.2 available)
Changed 6 dependencies!
8 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

Connected devices:

macOS (desktop)                 • macos                 • darwin-arm64   • macOS 14.4.1 23E224 darwin-arm64
Mac Designed for iPad (desktop) • mac-designed-for-ipad • darwin         • macOS 14.4.1 23E224 darwin-arm64
Chrome (web)                    • chrome                • web-javascript • Google Chrome 124.0.6367.208

No wireless devices were found.

[1]: macOS (macos)
[2]: Mac Designed for iPad (mac-designed-for-ipad)
[3]: Chrome (chrome)
Please choose one (or "q" to quit): 1

00:01 +0: loading /path/to/counter_app/integration_test/app_test.dart        R
00:02 +0: loading /path/to/counter_app/integration_test/app_test.dart    846ms
00:03 +0: loading /path/to/counter_app/integration_test/app_test.dart        B

Building macOS application...
✓ Built build/macos/Build/Products/Debug/counter_app.app
00:32 +1: All tests passed!
flutter test integration_test/app_test.dart

Connected devices:

Linux (desktop) • linux  • linux-x64      • Ubuntu 22.04.4 LTS 6.5.0-35-generic
Chrome (web)    • chrome • web-javascript • Google Chrome 104.0.5112.101

[1]: Linux (linux)
[2]: Chrome (chrome)

Please choose one (or "q" to quit): 1

00:00 +0: /path/to/counter_app/integration_test/app_test.dart     B
00:16 +0: /path/to/counter_app/integration_test/app_test.dart

✓ Built build/linux/x64/debug/bundle/counter_app

在 Android 设备上测试

#

在真实 Android 设备上测试,请完成以下任务。

  1. 连接 Android 设备。

  2. 在项目根目录运行:

    flutter test integration_test/app_test.dart
    

    结果应类似以下输出。

    flutter test integration_test/app_test.dart
    00:04 +0: loading /path/to/counter_app/integration_test/app_test.dart
    00:15 +0: loading /path/to/counter_app/integration_test/app_test.dart
    00:18 +0: loading /path/to/counter_app/integration_test/app_test.dart   2,387ms
    Installing build/app/outputs/flutter-apk/app.apk...  612ms
    00:21 +1: All tests passed!
    
  3. 确认测试结束后已移除计数器应用。否则后续测试会失败。必要时长按应用,在上下文菜单中选择 Remove App


在 iOS 设备上测试

#

在真实 iOS 设备上测试,请完成以下任务。

  1. 连接 iOS 设备。

  2. 在项目根目录运行:

    flutter test integration_test/app_test.dart
    

    结果应类似以下输出。

    flutter test integration_test/app_test.dart
    00:04 +0: loading /path/to/counter_app/integration_test/app_test.dart
    00:15 +0: loading /path/to/counter_app/integration_test/app_test.dart
    00:18 +0: loading /path/to/counter_app/integration_test/app_test.dart   2,387ms
    Xcode build done.                                           13.5s
    00:21 +1: All tests passed!
    
  3. 确认测试结束后已移除计数器应用。否则后续测试会失败。必要时长按应用,在上下文菜单中选择 Remove App


在 Web 浏览器中测试

#

在 Web 浏览器中测试,请按以下步骤操作。

  1. ChromeDriver 安装到你选择的目录。

    npx @puppeteer/browsers install chromedriver@stable
    

    为简化安装,该命令使用 @puppeteer/browsers Node library。

  2. 将 ChromeDriver 路径加入 $PATH 环境变量。

  3. 验证 ChromeDriver 安装成功。

    chromedriver --version
    ChromeDriver 124.0.6367.60 (8771130bd84f76d855ae42fbe02752b03e352f17-refs/branch-heads/6367@{#798})
    
  4. counter_app 项目目录中新建 test_driver 目录。

    mkdir test_driver
    
  5. 在该目录中新建 integration_test.dart 文件。

  6. 将以下代码复制并粘贴到 integration_test.dart 文件。

    test_driver/integration_test.dart
    dart
    import 'package:integration_test/integration_test_driver.dart';
    
    Future<void> main() => integrationDriver();
    
  7. 按以下方式启动 chromedriver

    chromedriver --port=4444
    
  8. 在项目根目录运行:

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

    响应应类似以下输出:

    Resolving dependencies...
      leak_tracker 10.0.0 (10.0.5 available)
      leak_tracker_flutter_testing 2.0.1 (3.0.5 available)
      leak_tracker_testing 2.0.1 (3.0.1 available)
      material_color_utilities 0.8.0 (0.11.1 available)
      meta 1.11.0 (1.14.0 available)
      test_api 0.6.1 (0.7.1 available)
      vm_service 13.0.0 (14.2.1 available)
    Got dependencies!
    7 packages have newer versions incompatible with dependency constraints.
    Try `flutter pub outdated` for more information.
    Launching integration_test/app_test.dart on Chrome in debug mode...
    Waiting for connection from debug service on Chrome...             10.9s
    This app is linked to the debug service: ws://127.0.0.1:51523/3lofIjIdmbs=/ws
    Debug service listening on ws://127.0.0.1:51523/3lofIjIdmbs=/ws
    00:00 +0: end-to-end test tap on the floating action button, verify counter
    00:01 +1: (tearDownAll)
    00:01 +2: All tests passed!
    All tests passed.
    Application finished.
    

    要以无头方式运行,请对 flutter drive 使用 -d web-server 选项:

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

更多信息请参阅 Running Flutter driver tests with web wiki 页面。


在 Firebase Test Lab 中测试(Android)

#

可使用 Firebase Test Lab 测试 Android 目标。

Android 设置

#

请遵循 README 中的 Android Device Testing 章节说明。

Test Lab 项目设置

#
  1. 打开 Firebase Console

  2. 如有需要,创建新的 Firebase 项目。

  3. 导航至 Quality > Test Lab

    Firebase Test Lab Console

上传 Android APK

#

完成以下步骤以上传 Android APK。

  1. 使用 Gradle 创建 APK。

    // Go to the Android directory which contains the gradlew script
    pushd android
    
    // Build a debug APK for Flutter with gradlew
    // Note that a standard --release build will not include package:integration_test
    flutter build apk --debug
    
    // Build an Android test APK
    ./gradlew app:assembleAndroidTest
    
    // Build a debug APK by passing in an integration test
    ./gradlew app:assembleDebug -Ptarget=integration_test/<name>_test.dart
    
    • <name>_test.dart: The file created in the Project Setup section.

    • <name>_test.dart:在 Project Setup 章节创建的文件。

  2. 如有需要,以逗号分隔列表向集成测试传入参数,并将所有参数编码为 base64

    ./gradlew project:task -Pdart-defines="{base64 (key=value)}[, ...]"
    
    • (key=value)}[, ...]: Replace this with a comma-separated list of key value pairs.

    • (key=value)}[, ...]:替换为逗号分隔的键值对列表。

  3. 返回之前的目录。

    popd
    

更多说明请参阅 README 的 Firebase Test Lab section

启动 Robo 测试

#

要使用 Robo 测试运行集成测试,请完成以下步骤。

  1. 将 debug APK 从 <flutter_project_directory>/build/app/outputs/apk/debug 拖到网页上的 Android Robo Test 目标。例如:

    Firebase Test Lab upload
  2. 点击 Run a test

  3. 选择 Instrumentation 测试类型。

  4. 将 App APK 添加到 App APK or AAB 框。

    <flutter_project_directory>/build/app/outputs/apk/debug/<file>.apk

  5. 将 Test APK 添加到 Test APK 框。

    <flutter_project_directory>/build/app/outputs/apk/androidTest/debug/<file>.apk

    Firebase Test Lab upload two APKs
  6. 若失败,点击红色图标查看输出:

    Firebase Test Lab test results

在 Firebase Test Lab 中测试(iOS)

#

可使用 Firebase Test Lab 测试 iOS 目标。

iOS 设置

#

请遵循 iOS Device Testing instructions

Test Lab 项目设置

#
  1. 打开 Firebase Console

  2. 如有需要,创建新的 Firebase 项目。

  3. 导航至 Quality > Test Lab

    Firebase Test Lab Console

通过 Firebase Console 上传 Xcode 测试

#

要了解如何通过 Firebase Test Lab Console 从 ZIP 文件上传测试,请参阅 Firebase Test Lab iOS instructions

通过命令行将 Xcode 测试上传到 Firebase Console

#

要了解如何从命令行将 ZIP 中的测试上传到 Firebase Test Lab Console,请参阅 iOS Device Testing instructions