flutter-add-integration-test
作者: flutter
配置 Flutter Driver 以進行應用互動,並將 MCP 操作轉換為永久性的整合測試。在為專案加入整合測試時使用,…
npx skills add https://github.com/flutter/skills --skill flutter-add-integration-testImplementing Flutter Integration Tests
Contents
- Project Setup and Dependencies
- Interactive Exploration via MCP
- Test Authoring Guidelines
- Execution and Profiling
- Workflow: End-to-End Integration Testing
- Examples
Project Setup and Dependencies
Configure the project to support integration testing and Flutter Driver extensions.
- Add required development dependencies to
pubspec.yaml:flutter pub add 'dev:integration_test:{"sdk":"flutter"}' flutter pub add 'dev:flutter_test:{"sdk":"flutter"}' - Enable the Flutter Driver extension in your application entry point (typically
lib/main.dartor a dedicatedlib/main_test.dart):- Import
package:flutter_driver/driver_extension.dart. - Call
enableFlutterDriverExtension();beforerunApp().
- Import
- Add
Keyparameters (e.g.,ValueKey('login_button')) to critical widgets in the application code to ensure reliable targeting during tests.
Interactive Exploration via MCP
Use the Dart/Flutter MCP server tools to interactively explore and manipulate the application state before writing static tests.
- Launch: Execute
launch_appwithtarget: "lib/main_test.dart"to start the application and acquire the DTD URI. - Inspect: Execute
get_widget_treeto discover availableKeys,Textnodes, and widgetTypes. - Interact: Execute
tap,enter_text, andscrollto simulate user flows. - Wait: Always execute
waitForor verify state withget_healthwhen navigating or triggering animations. - Troubleshoot Unmounted Widgets: If a widget is not found in the tree, it may be lazily loaded in a
SliverListorListView. ExecutescrollorscrollIntoViewto force the widget to mount before interacting with it.
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.dartconvention. - Initialize the binding by calling
IntegrationTestWidgetsFlutterBinding.ensureInitialized();at the start ofmain(). - Load the application UI using
await tester.pumpWidget(MyApp());. - Trigger frames and wait for animations to complete using
await tester.pumpAndSettle();after interactions liketester.tap(). - Assert widget visibility using
expect(find.byKey(ValueKey('foo')), findsOneWidget);orfindsNothing. - 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_drivertests, usedriver.waitFor(),driver.waitForAbsent(),driver.tap(), anddriver.scroll()instead of theWidgetTesterAPIs.
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=4444in 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):
- Build debug APK:
flutter build apk --debug - Build test APK:
./gradlew app:assembleAndroidTest - Upload both APKs to the Firebase Test Lab console.
- Build debug APK:
Workflow: End-to-End Integration Testing
Copy and follow this checklist to implement and verify integration tests.
- Task Progress: Setup
- Add
integration_testandflutter_testtopubspec.yaml. - Inject
enableFlutterDriverExtension()into the app entry point. - Assign
ValueKeys to target widgets.
- Add
- Task Progress: Exploration
- Run
launch_appvia MCP. - Map the widget tree using
get_widget_tree. - Validate interaction paths using MCP tools (
tap,enter_text).
- Run
- Task Progress: Authoring
- Create
integration_test/app_test.dart. - Write test cases using
WidgetTesterAPIs. - Create
test_driver/integration_test.dartwithintegrationDriver().
- Create
- 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
PumpAndSettleTimedOutExceptionoccurs, check for infinite animations -> If widget not found, addscrollUntilVisible-> Re-run test until passing.
- Run
Examples
Standard Integration Test (integration_test/app_test.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)
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() => integrationDriver();
Performance Profiling Driver Script (test_driver/perf_driver.dart)
Use this driver script if you wrap your test actions in binding.traceAction() to capture performance metrics.
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,
);
}
},
);
}
來自 flutter 的更多技能
dart-modern-features
flutter
為了尋找現代化的候選對象:
official
dart-log-failure-parser
flutter
解析 Dart 和 Flutter 測試日誌中的失敗資訊。
official
find-release
flutter
一個用來找出包含指定提交的最低Dart與Flutter版本的技能。每當使用者詢問某個提交何時被納入Flutter或Dart時,請使用此技能…
official
flutter-pr-checks-finder
flutter
在 Flutter PR 上找出失敗的檢查,並定位對應的 LUCI 日誌網址。
official
rebuilding-flutter-tool
flutter
重建 Flutter 工具與 CLI。當使用者要求編譯、更新、重新產生或重建 Flutter 工具或 CLI 時使用。
official
upgrade-browser
flutter
在 Flutter Web 引擎和/或框架測試中升級瀏覽器版本(Chrome 或 Firefox)。當被要求滾動或升級 Chrome 或 Firefox 至更新版本時使用。
official
create-catalog-item
flutter
當使用者要求在一個使用 JSON Schema 定義的應用程式中,根據該定義建立新的 CatalogItem、資料類別和/或 widget 類別時,使用此技能。
official
genui-helper
flutter
此技能提供 genui 儲存庫專屬的工作流程與最佳實踐。
official