Developing Integration Tests for Flutter Applications
Integration tests in Flutter run on a real device or emulator. The application starts completely: Dart engine, Flutter Framework, your code. WidgetTester here works on top of real rendering, not synthetic. That's why integration tests find what widget tests miss: issues with navigation between real Routes, animation timing on specific hardware, behavior under low memory.
The integration_test Package
The modern approach — the integration_test package from Flutter SDK (not third-party, official since Flutter 2.5). It replaces the deprecated flutter_driver.
pubspec.yaml:
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
Directory structure:
integration_test/
app_test.dart
test_driver/
integration_test.dart # only for running via flutter drive
Running on connected device:
flutter test integration_test/app_test.dart
Running in Firebase Test Lab or BrowserStack — through flutter build apk --target integration_test/app_test.dart + APK upload.
What We Test and How
A typical integration test covers a full user flow: opened app → authorized → navigated to catalog screen → added item to cart → completed order → saw confirmation screen.
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Full checkout flow', (tester) async {
app.main();
await tester.pumpAndSettle();
// Login
await tester.enterText(find.byKey(Key('email')), '[email protected]');
await tester.enterText(find.byKey(Key('password')), 'password123');
await tester.tap(find.byKey(Key('login_btn')));
await tester.pumpAndSettle(timeout: Duration(seconds: 10));
expect(find.byKey(Key('home_screen')), findsOneWidget);
// Add to cart
await tester.tap(find.byKey(Key('product_card_1')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(Key('add_to_cart_btn')));
await tester.pumpAndSettle();
expect(find.text('1'), findsOneWidget); // badge on cart icon
});
}
pumpAndSettle(timeout: Duration(seconds: 10)) — timeout is necessary. Without it on a slow emulator the test will fail before navigation animation completes.
Parallel Execution
One test file — one device session. For parallel runs create multiple files and run them through a matrix in CI. In GitHub Actions:
strategy:
matrix:
test-file: [auth_test.dart, checkout_test.dart, profile_test.dart]
steps:
- run: flutter test integration_test/${{ matrix.test-file }}
Each job gets its own emulator. AVD Manager through reactivecircus/android-emulator-runner@v2 runs them in parallel.
Working with Real Network Requests
The main choice: test against a real backend or mock the network.
Real backend — need a test environment (staging). Data must be predictable: fixed test accounts, deterministic responses. Network errors make tests unstable.
Mock server — mockito/mocktail at the repository level, or local HTTP server through shelf package. The second approach is closer to reality: the application makes a real HTTP request, but to localhost:8080 instead of api.production.com. Switching through environment variable or --dart-define=API_BASE_URL=http://localhost:8080.
Integration Test Instability
Flaky tests in integration_test — common problem. Main causes:
Animations. pumpAndSettle() waits for their completion, but if your app has an infinite animation (loading indicator, lottie animation in background), pumpAndSettle() will hang. Solution: tester.pump(Duration(milliseconds: 500)) with explicit waiting for specific widget through waitFor.
Keyboard. After enterText() system keyboard may cover button. Hide it: await tester.testTextInput.receiveAction(TextInputAction.done) or FocusManager.instance.primaryFocus?.unfocus() before tap().
Test timeout. By default integration test completes in 10 minutes. For long flows increase: @Timeout(Duration(minutes: 5)) above testWidgets.
Timeline
3–5 days for writing integration tests to existing application. Complex flow with authorization, payments, and deep navigation — closer to 5 days. Simple linear scenarios — 3 days. Cost is calculated after architecture audit of the application.







