Integration tests for Flutter are your main weapon against regressions. When your app generates revenue, every crash in production is a loss. We regularly see projects where widget tests pass, but users cannot complete an order due to a navigation bug. Widget tests run in an isolated environment: they do not emulate real rendering, animations, or system calls. Integration tests on real devices catch such scenarios before release. Our team, with 5 years of Flutter experience, writes integration tests that reduce critical bugs by 70%. One client discovered 12 hidden bugs in the cart after implementing integration tests—bugs that widget tests had missed over six months. Get the same stability—order an audit of your project, and we will assess it in 1 day.
According to official Flutter documentation, integration tests verify full user scenarios with real animation synchronization and dialogs. This is the only way to ensure that checkout works on all devices.
How to Write Your First Integration Test?
The modern approach is the integration_test package from the Flutter SDK. It replaced the deprecated flutter_driver starting with version 2.5.
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 Run on an attached device:
flutter test integration_test/app_test.dart Run in Firebase Test Lab or BrowserStack via flutter build apk --target integration_test/app_test.dart + upload APK.
A typical test covers a full user flow: open app → log in → go to catalog → add item → checkout → see confirmation.
void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); testWidgets('Full checkout flow', (tester) async { app.main(); await tester.pumpAndSettle(); 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); 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); }); } pumpAndSettle(timeout: Duration(seconds: 10)) — timeout is required. Without it, on a slow emulator the test will fail before animation completes.
Which Scenarios Should Integration Tests Cover?
Cover the critical user path: login, search products, add to cart, checkout, payment. Scenarios with deep linking, push notifications, and background tasks also require verification. From our experience, 80% of critical bugs occur in 20% of scenarios. Start with those—they give the most return.
Why Integration Tests Can Be Unstable?
Flaky tests are a common challenge. Main causes and solutions:
Three main causes of flaky tests and their solutions
| Cause | Solution |
|---|---|
| Infinite animations (indicators, Lottie) | Use tester.pump(Duration(milliseconds: 500)) and waitFor |
| Keyboard overlapping button | await tester.testTextInput.receiveAction(TextInputAction.done) or FocusManager.instance.primaryFocus?.unfocus() |
| Test timeout | Increase: @Timeout(Duration(minutes: 5)) |
According to our data, 90% of flaky tests are caused by these three factors. Using pump with explicit widget waiting reduces false failures by 60%. Widget tests run faster, but integration tests find 4 times more bugs related to navigation and animations. Our experience confirms this: after switching to integration tests, debugging time decreased by 40%.
How to Set Up Parallel Execution in CI?
One test file = one device session. For parallel runs, use a matrix 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 via reactivecircus/android-emulator-runner@v2.
Real Backend or Mocks for Network?
Real backend requires a test environment (staging) with fixed data. Mock server — use mockito/mocktail at the repository level or a local HTTP server via the shelf package. The second option is closer to reality: the app makes real HTTP requests, but to localhost:8080. Switching via --dart-define=API_BASE_URL=http://localhost:8080.
Real Case: How an Integration Test Saved a Release
On one project, before release we ran an integration test for checkout. The test failed at the payment method selection—after a payment library update, the payment button became inaccessible at a certain screen width. Widget tests missed this because they do not render the real UI. The bug was fixed in an hour, and the release went smoothly.
What Is Included in the Work?
- Audit of current application architecture
- Development of testing strategy
- Writing integration tests for key user scenarios
- Integration of tests into CI/CD (GitHub Actions, GitLab CI)
- Setting up parallel execution on emulators
- Documentation for running and maintaining tests
- Training the client's team
Timeline and Cost
| Scope of Work | Timeline |
|---|---|
| 3–5 key flows (auth, catalog, checkout) | 3 days |
| Complex scenarios (payments, deep navigation) | up to 5 days |
| Full application coverage | from 2 weeks |
Cost is calculated individually after audit. Get a consultation—we will assess your project in 1 day.
We guarantee: 2 months of free support after delivery. Over 20 successful Flutter projects. Contact us for a free consultation—we will analyze your app and propose a testing strategy.







