Flutter · One codebase, native feel
How do you run integration tests on devices?
Short answer
Use the integration_test package to drive the app on a real device or emulator. Keep journeys small and deterministic, stub external services, and run them in CI with managed devices.
Integration tests run the full app, including plugins and real navigation. They catch problems that widget tests cannot, but they are slower and more environment-dependent. A good suite covers a few critical journeys rather than every screen.
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('login and open orders', (tester) async {
await tester.pumpWidget(const App());
await tester.enterText(find.byKey(const Key('email')), 'qa@example.com');
await tester.enterText(find.byKey(const Key('password')), 'secret123');
await tester.tap(find.byKey(const Key('login')));
await tester.pumpAndSettle();
expect(find.text('Orders'), findsOneWidget);
});
}- Use a dedicated test account and reset backend state before each run
- Stub or sandbox third-party services so tests do not depend on live data
- Prefer accessibility keys over visible text for stable finders
- Capture screenshots and logs on failure for diagnosis
- Run on a small device matrix, not every model, to control cost and time
Reducing flakiness
Flakiness usually comes from timing, shared backend state or real network conditions. Replace arbitrary delays with condition-based waits. Make test data unique per run. If a journey needs a push notification or permission dialog, handle the platform prompt explicitly or exclude that path from the automated suite and test it manually.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1Which journeys deserve an integration test?
- 2How do you handle permission dialogs in an automated run?
- 3What causes integration tests to be flaky?
- 4How would you run these tests in CI?
Say it in the interview
I use integration_test for a small set of critical journeys because it runs the real app with real plugins. Each test gets a dedicated account and unique data, and external services are sandboxed. I avoid fixed sleeps and wait on conditions instead. In CI I run them on a limited device matrix and capture logs and screenshots on failure.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Flutter mock interview and get scored feedback on depth, clarity and confidence.