Flutter 测试的最新进展
Flutter 的目标是提供一个开放的框架,以帮助您快速构建精美的多平台原生应用。为了实现该目标,让您能够轻松测试 Flutter 应用也是工作内容的重要一环,以确保它们在目标平台上的功能和显示效果与您的预期相符。使用 Dart 内置单元测试框架编写的单元测试可以处理其中一部分测试。Dart 单元测试对于非界面测试非常有效,它可以在您的开发计算机上运行,同时不依赖 Flutter 应用的 GUI (图形用户界面)。
Dart 里的测试
https://dart.cn/guides/testing
集成测试 (也称为端到端测试或 GUI 测试) 比起单元测试而言更进一步,因为集成测试会试图模拟用户按下按钮、选择条目以及在键盘上打字等操作,从而与您的应用进行交互。集成测试是完全自动化的,以避免以人工方式处理此类重复性工作,而且坦白地讲,繁重且重复的工作并不是我们的强项。我们最初制定的避免人为干预的解决方案是以特殊方式编写 Flutter 测试,这些测试与 Dart 单元测试一样在主机上运行,并会像人为操作那样在真实或虚拟设备上运行应用。这些测试被称为 Flutter driver (驱动程序) 测试,因为您需要使用 flutter_driver package 和 flutter drive 命令行来驱动应用的 GUI。
遗憾的是,Flutter driver 测试存在很多问题。其中的一个问题是,测试需要在开发机器上运行并与设备上的应用进行通信,这意味着这些测试不适合在诸如 Firebase Test Lab 等设备库中运行。另一个问题是,由于测试是一个独立的流程,因此难以检查应用的状态。您可以检查输出,但是诸如应用的内部状态等信息将不得而知。最后一个问题是,flutter_driver API 过于复杂,尤其是在编写代码以在屏幕上找到想要测试的 widget 时。
-
Firebase Test Lab https://firebase.google.cn/docs/test-lab
为了解决这些问题并在目标平台日益增多的情况下继续提升 Flutter 测试体验,我们很高兴地发布 1.0 版本的 integration_test 插件,它为测试 Flutter 应用提供了更简单的解决方案,而且支持 Firebase Test Lab。
-
integration_test 插件 https://pub.flutter-io.cn/packages/integration_test
开始使用 integration_test
使用 integration_test 插件需要两个步骤。首先,将插件作为开发依赖项添加到 pubspec.yaml 文件,然后使用 flutter pub get 将插件拉取到您的项目中:
# pubspec.yaml
…
dev_dependencies:
flutter_test:
sdk: flutter
integration_test: ^1.0.0
…
随后,在测试代码中使用 integration_test package:
// widget_integration_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hello_world/main.dart';
import 'package:integration_test/integration_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the + icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
值得注意的是,您需要导入 integration_test package 并且调用 IntegrationTestWidgetsFlutterBinding.ensureInitialized(),这可确保对 package 执行正确的初始化。另外请注意标准的 WidgetTester 测试代码,这与在运行 flutter create 时由默认 Counter 应用模板生成的测试代码相同。
尽管 integration_test 能够使您的测试以独立形式捆绑到您的应用中 (这是 Firebase Test Lab 等设备库的要求),在构建方面却需要一些特殊技巧,我们将在下文中介绍。然而,在测试开发过程中,能够通过命令行来交互式运行测试将会非常方便,为此,您需要一个新的操作入口:
// integration_test.dart
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() => integrationDriver();
调用 IntegrationDriver 可方便地封装 IntegrationDriver 插件,随后,您便可以使用 flutter drive 命令运行新的测试:
flutter drive \
--driver=test_driver/integration_test.dart \
--target=test/widget_integration_test.dart
此命令会将您的应用部署到模拟器、执行测试并显示测试结果。
上面这个测试是在 iOS 平台上运行的,但您也可以更改 --device-id 选项,从而让 integration_test 插件用于 Android 平台。此外,您也可以针对网页和桌面目标平台运行集成测试 (此功能尚处于预发布状态)。
在 Firebase Test Lab 上运行
在确定可以使用虚拟或物理硬件在本地运行测试之后,您现在可以将应用部署到 Firebase Test Lab 中大量的设备上。
Firebase Test Lab 是基于云的应用测试基础架构。只需一次操作,就可以对您的 Android 或 iOS 应用执行覆盖多种设备和设备配置的测试,并在 Firebase 控制台中查看包括日志、视频和屏幕截图在内的测试结果。Integration_test 插件的主要优势之一是能够在 Firebase Test Lab 中运行 Android 和 iOS 平台的 Flutter 应用,使您能够同时进行跨数百种设备的测试,从而在发布应用之前发现具体平台、配置或具体设备中存在的特定问题。
集成测试
https://flutter.cn/docs/testing/integration-tests
从 Flutter driver 测试迁移
如果您已经在使用 flutter_driver 测试,那么迁移到新的 API 不会太难。除了上文中提到的适当的初始化工作之外,您还需要迁移到新的 WidgetTester API。
从概念上讲,flutter_driver API (如上左图所示) 与 WidgetTester API (上方右图所示) 非常相似,但是您可以看到它们在细节方面有很多不同之处。例如,在 flutter_driver 上需要调用 waitFor 方法,而在 WidgetTester 上却需要调用 pumpAndSettle 方法。前者会等待特定的 widget 出现,而后者则等待应用的界面完成渲染。获得特定 widget 后,在两种 API 下可对其进行类似的操作,但需要使用不同的对象。WidgetTest API 更符合您在 Dart 单元测试中常见的工作方式,比如,通过 expect 方法来确保 widget 的内容与预期相符。
有关如何将测试从 flutter_driver 迁移至 integration_test,以及 WidgetTester 的详细信息,请参阅 flutter.dev 上的迁移文档。
-
从 flutter_driver 迁移 http://flutter.cn/docs/testing/integration-tests#migrating-from-flutter_driver
原生界面测试
如果您要使用 Add-to-App 来将 Flutter 添加至现有的 Android 或 iOS 应用,那么您可能需要沿用之前针对原生应用编写的集成测试。在这种情况下,请将针对 Flutter 界面的测试添加到这些现有的测试中即可。对于 Android,您可以使用 espresso 插件添加通过 Espresso 框架编写的测试,这样可为 Flutter Android 应用的 Espresso 测试提供绑定。我们不久会发布一款类似的插件来支持使用 Earl Grey 创建的原生 iOS 测试。
-
使用 Add-to-App 将 Flutter 集成到现有应用 https://flutter.cn/docs/development/add-to-app -
Espresso 插件 https://pub.flutter-io.cn/packages/espresso
总结
此次更新为使用新的 integration_test 插件对 Flutter 进行集成测试奠定了新的基础。不仅 API 更加简单一致,还可以使用 Firebase Test Lab 在数百种不同的设备上运行使用 integration_test 编写的测试。Flutter 团队计划在这一全新基础上进一步提升,其中包括更新 flutter create 模板以默认支持使用 integration_test,更新测试输出以支持使用 JUnit 格式的现有测试工具,以及增加在测试期间进行截图的功能以实现 Golden 对比测试等等。我们针对 Flutter 应用和插件提供了新的集成测试建议,请参阅 flutter.dev 上的测试文档了解详情。
集成测试
https://flutter.cn/docs/testing/integration-tests
本文特别鸣谢: Filip Hracek
推荐阅读