集成测试

本篇描述了如何使用 integration_test package 来运行集成测试。使用该 package 编写的测试具有以下特性:

  • 兼容 flutter drive 指令,用于在真机或模拟器上运行测试。

  • 能够通过 Firebase Test Lab 在各种设备上进行自动化测试。

  • 兼容 flutter_test API,能够使用类似 widget 测试 的风格进行编写。

概览

单元测试、Widget 测试和集成测试

Flutter 支持三种类型的测试。 单元测试 验证一个方法或类的行为。 Widget 测试 无需运行应用程序就可以验证 Flutter widget 的行为。 集成测试(又名端到端测试或 GUI 测试)运行整个应用程序。

宿主和目标设备

在开发过程中,宿主 就是你的编码平台,应用程序在 目标 设备上运行,就像你在台式电脑上编写代码,并在移动设备、浏览器或者桌面程序上运行你的应用程序,(如果你使用的是 web 浏览器或桌面应用程序,宿主也是目标设备)

integration_test

integration_test package

integration_test package 编写的测试可以:

  1. 直接在目标设备上运行,允许使用 Firebase Test Lab 在多个 Android/iOS 设备上进行测试。

  2. 使用 flutter test integration_test 指令运行。

  3. 使用 flutter_test API,让集成测试编写风格更像 Widget 测试

从 flutter_driver 迁移

现在还在使用 flutter_driver 的项目可以通过以下方式迁移到 integration_test,请查看 从 flutter_driver 迁移 指南。

项目设置

在你的 pubspec.yaml 文件中加入 integration_testflutter_test

$ flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'  'dev:integration_test:{"sdk":"flutter"}'
"flutter_test" is already in "dev_dependencies". Will try to update the constraint.
Resolving dependencies... 
  collection 1.17.2 (1.18.0 available)
+ file 6.1.4 (7.0.0 available)
+ 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
  material_color_utilities 0.5.0 (0.8.0 available)
  meta 1.9.1 (1.10.0 available)
+ platform 3.1.0 (3.1.2 available)
+ process 4.2.4 (5.0.0 available)
  stack_trace 1.11.0 (1.11.1 available)
  stream_channel 2.1.1 (2.1.2 available)
+ sync_http 0.3.1
  test_api 0.6.0 (0.6.1 available)
+ vm_service 11.7.1 (11.10.0 available)
+ webdriver 3.0.2
Changed 9 dependencies!

在你的项目中,创建一个 integration_test 目录,新目录中创建一个新文件 <name>_test.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() {
  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 Key('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('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });
}

如果你想了解更多示例,请查看 samples 中的 testing_app

目录结构

lib/
  ...
integration_test/
  foo_test.dart
  bar_test.dart
test/
  # Other unit tests go here.

另见:

使用 Flutter 指令运行测试

这些测试可以用 flutter test 指令运行,其中 <DEVICE_ID>:是可选项,可以通过 flutter devices 指定设备 ID 或显示模式:

$ flutter test integration_test/foo_test.dart -d <DEVICE_ID>

上面的指令将运行 foo_test.dart 中的测试。要在默认设备上运行该目录下的所有测试,请运行:

$ flutter test integration_test

在浏览器中运行测试

下载安装 ChromeDriver 并在 4444 端口运行:

$ chromedriver --port=4444

为了使用 flutter drive 进行测试,请创建一个新的目录,其中包含一个新的文件 test_driver/integration_test.dart

import 'package:integration_test/integration_test_driver.dart';

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

然后将 IntegrationTestWidgetsFlutterBinding.ensureInitialized() 添加到你的 integration_test/<name>_test.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(); // NEW

  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 Key('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('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });
}

最后在一个独立的进程中,运行 flutter_drive

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

了解更多信息,请查看 Running Flutter driver tests with web 指南。

在 Firebase Test Lab 进行测试

你可以通过 Firebase Test Lab 同时使用 Android 和 iOS 目标设备进行测试。

Android 设置

请遵循 integration_test README 中的 Android Device Testing 进行设置。

iOS 设置

请遵循 integration_test README 中的 iOS Device Testing 进行设置。

Firebase Test Lab 项目设置

进入 Firebase 控制台, 如果你还没有新的项目,就创建一个新项目。然后导航菜单到 Quality > Test Lab:

Firebase Test Lab Console

上传 Android APK

使用 Gradle 构建一个 APK:

$ pushd android
# flutter build generates files in android/ for building the app
flutter build apk
./gradlew app:assembleAndroidTest
./gradlew app:assembleDebug -Ptarget=integration_test/<name>_test.dart
$ popd

上面指令中的 <name>_test.dart 是在刚才 项目设置 创建的文件。

<flutter_project_directory>/build/app/outputs/apk/debug 内打包完成的 “debug” APK 文件上传到网页上的 Android Robo Test。这将启动一个 Robo 测试,并允许你运行其他测试:

Firebase Test Lab upload

点击 Run a test, 选择 Instrumentation 测试类型,并上传以下两个文件

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

Firebase Test Lab upload two APKs

如果发生故障,你可以通过选择红色图标查看输出内容:

Firebase Test Lab test results

通过指令上传 Android APK

关于通过指令上传 APK 的说明,请查看 integration_test README 中的 Firebase Test Lab

上传 Xcode 测试

了解如何将 .zip 文件上传到 Firebase 控制台的 Firebase Test Lab,请查看 Firebase TestLab iOS instructions

通过指令上传 Xcode 测试

关于如何通过指令上传 .zip 文件的说明,请查看 integration_test README 中的 iOS Device Testing