vlambda博客
学习文章列表

Flutter 测试的最新进展

作者 / Chris Sells, 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.yamldev_dependencies: flutter_test: sdk: flutter integration_test: ^1.0.0

随后,在测试代码中使用 integration_test package:

// widget_integration_test.dartimport '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.dartimport '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

此命令会将您的应用部署到模拟器、执行测试并显示测试结果。

△ Flutter integration_test 运行截图

上面这个测试是在 iOS 平台上运行的,但您也可以更改 --device-id 选项,从而让 integration_test 插件用于 Android 平台。此外,您也可以针对网页和桌面目标平台运行集成测试 (此功能尚处于预发布状态)。



在 Firebase Test Lab 上运行


在确定可以使用虚拟或物理硬件在本地运行测试之后,您现在可以将应用部署到 Firebase Test Lab 中大量的设备上。

Flutter 测试的最新进展
△ Firebase Test Lab 控制台

Firebase Test Lab 是基于云的应用测试基础架构。只需一次操作,就可以对您的 Android 或 iOS 应用执行覆盖多种设备和设备配置的测试,并在 Firebase 控制台中查看包括日志、视频和屏幕截图在内的测试结果。Integration_test 插件的主要优势之一是能够在 Firebase Test Lab 中运行 Android 和 iOS 平台的 Flutter 应用,使您能够同时进行跨数百种设备的测试,从而在发布应用之前发现具体平台、配置或具体设备中存在的特定问题。


要在 Firebase Test Lab 中运行测试,您需要根据实际情况进行一些配置并使用 Gradle 命令构建针对 Android 和 iOS 平台的插桩测试。有关详细信息,请参阅 flutter.dev 上的新版集成测试文档

  • 集成测试

    https://flutter.cn/docs/testing/integration-tests



从 Flutter driver 测试迁移


如果您已经在使用 flutter_driver 测试,那么迁移到新的 API 不会太难。除了上文中提到的适当的初始化工作之外,您还需要迁移到新的 WidgetTester API。

Flutter 测试的最新进展
△ flutter_driver API (左图) 和 WidgetTesting 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



Flutter 测试的最新进展

推荐阅读






Flutter 测试的最新进展  点击屏末  | 访问 Flutter 开发者社区中文资源



Flutter 测试的最新进展