flutter-add-integration-test

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Implementing Flutter Integration Tests

实现Flutter集成测试

Contents

目录

Project Setup and Dependencies

项目设置与依赖

Configure the project to support integration testing and Flutter Driver extensions.
  1. Add required development dependencies to
    pubspec.yaml
    :
    bash
    flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
    flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'
  2. Enable the Flutter Driver extension in your application entry point (typically
    lib/main.dart
    or a dedicated
    lib/main_test.dart
    ):
    • Import
      package:flutter_driver/driver_extension.dart
      .
    • Call
      enableFlutterDriverExtension();
      before
      runApp()
      .
  3. Add
    Key
    parameters (e.g.,
    ValueKey('login_button')
    ) to critical widgets in the application code to ensure reliable targeting during tests.
配置项目以支持集成测试和Flutter Driver扩展。
  1. pubspec.yaml
    添加必要的开发依赖:
    bash
    flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
    flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'
  2. 在应用入口(通常是
    lib/main.dart
    或专用的
    lib/main_test.dart
    )中启用Flutter Driver扩展:
    • 导入
      package:flutter_driver/driver_extension.dart
    • runApp()
      之前调用
      enableFlutterDriverExtension();
  3. 在应用代码中的关键组件上添加
    Key
    参数(例如
    ValueKey('login_button')
    ),以确保测试期间能可靠定位组件。

Interactive Exploration via MCP

通过MCP进行交互式探索

Use the Dart/Flutter MCP server tools to interactively explore and manipulate the application state before writing static tests.
  • Launch: Execute
    launch_app
    with
    target: "lib/main_test.dart"
    to start the application and acquire the DTD URI.
  • Inspect: Execute
    get_widget_tree
    to discover available
    Key
    s,
    Text
    nodes, and widget
    Type
    s.
  • Interact: Execute
    tap
    ,
    enter_text
    , and
    scroll
    to simulate user flows.
  • Wait: Always execute
    waitFor
    or verify state with
    get_health
    when navigating or triggering animations.
  • Troubleshoot Unmounted Widgets: If a widget is not found in the tree, it may be lazily loaded in a
    SliverList
    or
    ListView
    . Execute
    scroll
    or
    scrollIntoView
    to force the widget to mount before interacting with it.
使用Dart/Flutter MCP服务器工具,在编写静态测试前交互式探索和操作应用状态。
  • 启动:执行
    launch_app
    并设置
    target: "lib/main_test.dart"
    以启动应用并获取DTD URI。
  • 检查:执行
    get_widget_tree
    以发现可用的
    Key
    Text
    节点和组件
    Type
  • 交互:执行
    tap
    enter_text
    scroll
    来模拟用户流程。
  • 等待:在导航或触发动画时,务必执行
    waitFor
    或通过
    get_health
    验证状态。
  • 排查未挂载组件问题:如果组件未在树中找到,它可能是在
    SliverList
    ListView
    中懒加载的。在交互前执行
    scroll
    scrollIntoView
    以强制组件挂载。

Test Authoring Guidelines

测试编写指南

Structure integration tests using the
flutter_test
API paradigm.
  • Create a dedicated
    integration_test/
    directory at the project root.
  • Name all test files using the
    <name>_test.dart
    convention.
  • Initialize the binding by calling
    IntegrationTestWidgetsFlutterBinding.ensureInitialized();
    at the start of
    main()
    .
  • Load the application UI using
    await tester.pumpWidget(MyApp());
    .
  • Trigger frames and wait for animations to complete using
    await tester.pumpAndSettle();
    after interactions like
    tester.tap()
    .
  • Assert widget visibility using
    expect(find.byKey(ValueKey('foo')), findsOneWidget);
    or
    findsNothing
    .
  • Scroll to specific off-screen widgets using
    await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder);
    .
Conditional Logic for Legacy
flutter_driver
:
  • If maintaining or migrating legacy
    flutter_driver
    tests, use
    driver.waitFor()
    ,
    driver.waitForAbsent()
    ,
    driver.tap()
    , and
    driver.scroll()
    instead of the
    WidgetTester
    APIs.
遵循
flutter_test
API范式构建集成测试。
  • 在项目根目录创建专用的
    integration_test/
    目录。
  • 所有测试文件使用
    <name>_test.dart
    命名规范。
  • main()
    开头调用
    IntegrationTestWidgetsFlutterBinding.ensureInitialized();
    初始化绑定。
  • 使用
    await tester.pumpWidget(MyApp());
    加载应用UI。
  • tester.tap()
    等交互后,使用
    await tester.pumpAndSettle();
    触发帧并等待动画完成。
  • 使用
    expect(find.byKey(ValueKey('foo')), findsOneWidget);
    findsNothing
    断言组件可见性。
  • 使用
    await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder);
    滚动到特定的屏幕外组件。
针对旧版
flutter_driver
的条件逻辑:
  • 如果维护或迁移旧版
    flutter_driver
    测试,请使用
    driver.waitFor()
    driver.waitForAbsent()
    driver.tap()
    driver.scroll()
    替代
    WidgetTester
    API。

Execution and Profiling

执行与性能分析

Execute tests using the
flutter drive
command. Require a host driver script located in
test_driver/integration_test.dart
that calls
integrationDriver()
.
Conditional Execution Targets:
  • If testing on Chrome: Launch
    chromedriver --port=4444
    in a separate terminal, then run:
    flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d chrome
  • If testing headless web: Run with
    -d web-server
    .
  • If testing on Android (Local): Run
    flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart
    .
  • If testing on Firebase Test Lab (Android):
    1. Build debug APK:
      flutter build apk --debug
    2. Build test APK:
      ./gradlew app:assembleAndroidTest
    3. Upload both APKs to the Firebase Test Lab console.
使用
flutter drive
命令执行测试。需要位于
test_driver/integration_test.dart
中的宿主驱动脚本,该脚本调用
integrationDriver()
条件执行目标:
  • 如果在Chrome上测试:在单独终端启动
    chromedriver --port=4444
    ,然后运行:
    flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d chrome
  • 如果测试无头Web:使用
    -d web-server
    运行。
  • 如果在本地Android上测试:运行
    flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart
  • 如果在Firebase Test Lab(Android)上测试
    1. 构建调试APK:
      flutter build apk --debug
    2. 构建测试APK:
      ./gradlew app:assembleAndroidTest
    3. 将两个APK上传到Firebase Test Lab控制台。

Workflow: End-to-End Integration Testing

工作流:端到端集成测试

Copy and follow this checklist to implement and verify integration tests.
  • Task Progress: Setup
    • Add
      integration_test
      and
      flutter_test
      to
      pubspec.yaml
      .
    • Inject
      enableFlutterDriverExtension()
      into the app entry point.
    • Assign
      ValueKey
      s to target widgets.
  • Task Progress: Exploration
    • Run
      launch_app
      via MCP.
    • Map the widget tree using
      get_widget_tree
      .
    • Validate interaction paths using MCP tools (
      tap
      ,
      enter_text
      ).
  • Task Progress: Authoring
    • Create
      integration_test/app_test.dart
      .
    • Write test cases using
      WidgetTester
      APIs.
    • Create
      test_driver/integration_test.dart
      with
      integrationDriver()
      .
  • Task Progress: Execution & Feedback Loop
    • Run
      flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart
      .
    • Feedback Loop: Review test output -> If
      PumpAndSettleTimedOutException
      occurs, check for infinite animations -> If widget not found, add
      scrollUntilVisible
      -> Re-run test until passing.
复制并遵循此检查清单以实现和验证集成测试。
  • 任务进度:设置
    • pubspec.yaml
      添加
      integration_test
      flutter_test
    • 在应用入口注入
      enableFlutterDriverExtension()
    • 为目标组件分配
      ValueKey
  • 任务进度:探索
    • 通过MCP运行
      launch_app
    • 使用
      get_widget_tree
      映射组件树。
    • 使用MCP工具(
      tap
      enter_text
      )验证交互路径。
  • 任务进度:编写
    • 创建
      integration_test/app_test.dart
    • 使用
      WidgetTester
      API编写测试用例。
    • 创建包含
      integrationDriver()
      test_driver/integration_test.dart
  • 任务进度:执行与反馈循环
    • 运行
      flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart
    • 反馈循环:查看测试输出 -> 如果出现
      PumpAndSettleTimedOutException
      ,检查是否存在无限动画 -> 如果未找到组件,添加
      scrollUntilVisible
      -> 重新运行测试直到通过。

Examples

示例

Standard Integration Test (
integration_test/app_test.dart
)

标准集成测试(
integration_test/app_test.dart

dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.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);

      // Find 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 and wait for animations.
      await tester.pumpAndSettle();

      // Verify the counter increments by 1.
      expect(find.text('1'), findsOneWidget);
    });
  });
}
dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.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);

      // Find 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 and wait for animations.
      await tester.pumpAndSettle();

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

Host Driver Script (
test_driver/integration_test.dart
)

宿主驱动脚本(
test_driver/integration_test.dart

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

Future<void> main() => integrationDriver();
dart
import 'package:integration_test/integration_test_driver.dart';

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

Performance Profiling Driver Script (
test_driver/perf_driver.dart
)

性能分析驱动脚本(
test_driver/perf_driver.dart

Use this driver script if you wrap your test actions in
binding.traceAction()
to capture performance metrics.
dart
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() {
  return integrationDriver(
    responseDataCallback: (data) async {
      if (data != null) {
        final timeline = driver.Timeline.fromJson(
          data['scrolling_timeline'] as Map<String, dynamic>,
        );

        final summary = driver.TimelineSummary.summarize(timeline);

        await summary.writeTimelineToFile(
          'scrolling_timeline',
          pretty: true,
          includeSummary: true,
        );
      }
    },
  );
}
如果您将测试操作包装在
binding.traceAction()
中以捕获性能指标,请使用此驱动脚本。
dart
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() {
  return integrationDriver(
    responseDataCallback: (data) async {
      if (data != null) {
        final timeline = driver.Timeline.fromJson(
          data['scrolling_timeline'] as Map<String, dynamic>,
        );

        final summary = driver.TimelineSummary.summarize(timeline);

        await summary.writeTimelineToFile(
          'scrolling_timeline',
          pretty: true,
          includeSummary: true,
        );
      }
    },
  );
}