Skip to content

Expert · Responsive design and testing · topic 42 of 50 · 30 min

Integration tests and CI

Explanation

Integration tests run the whole app on a real device or emulator and follow complete user journeys, using the integration_test package with the same finders and actions as widget tests. Run them with flutter test integration_test. Keep quality high automatically: flutter analyze for static analysis, dart format for consistent style, and a CI workflow (for example GitHub Actions) that runs analysis and tests on every push.

The testing pyramid

Fast unit tests form the base (many), widget tests the middle (some), and integration tests the top (a few). Integration tests are slower and more fragile because they start the real app on a device, but they are the only ones that prove a full journey works end to end: launch, log in, add to cart, pay.

output
        /\          integration tests: few, slow, whole app on a device
       /  \
      /----\        widget tests: some, fast, one screen at a time
     /      \
    /--------\      unit tests: many, very fast, pure logic
Aim for many fast tests and a few critical end-to-end ones.

Writing an integration test

yaml
# pubspec.yaml
dev_dependencies:
  integration_test:
    sdk: flutter
  flutter_test:
    sdk: flutter
integration_test ships with the Flutter SDK.
dart
// integration_test/order_flow_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:chai_shop/main.dart' as app;

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('user can add chai and see it in the cart', (tester) async {
    app.main();                                    // start the real app
    await tester.pumpAndSettle();

    await tester.tap(find.text('Masala chai'));
    await tester.pumpAndSettle();
    await tester.tap(find.text('Add to cart'));
    await tester.tap(find.byIcon(Icons.shopping_cart));
    await tester.pumpAndSettle();

    expect(find.text('Masala chai x1'), findsOneWidget);
  });
}
Same API as widget tests, but the whole app runs on a device.
bash
flutter test integration_test                       # on the connected device or emulator
flutter test integration_test/order_flow_test.dart
Use test accounts and a test backend, never real payments or production data.

Golden tests are another tool: they render a widget and compare it pixel by pixel with a saved reference image, catching accidental visual changes. They are useful for design systems but can be sensitive to fonts and platforms.

Choose integration tests for the journeys that make or lose money and trust: sign-up and login, search to checkout, booking and payment. Keep each test independent, start from a known state (for example a fresh test account or seeded test data), and avoid depending on exact timings; use finders and pumpAndSettle instead of fixed waits.

Integration tests can also run on cloud device farms such as Firebase Test Lab, which run your tests on many real phone models. This is useful for catching problems that appear only on certain manufacturers or Android versions.

Static analysis and formatting

bash
flutter analyze          # finds errors, warnings and lint issues without running the app
dart format .            # formats all Dart files in the standard style
dart format --output=none --set-exit-if-changed .   # CI check: fail if anything is unformatted
Lint rules come from analysis_options.yaml (flutter_lints by default).

Fix analyzer warnings as they appear; a clean analyzer is a good team habit.

CI: tests on every push

Continuous integration (CI) means a server automatically checks every change. With GitHub Actions, a small YAML file runs analysis and tests whenever someone pushes or opens a pull request; a failing check blocks broken code from being merged.

yaml
name: flutter-ci
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2      # a widely used community action to install Flutter
        with:
          channel: stable
      - run: flutter pub get
      - run: dart format --output=none --set-exit-if-changed .
      - run: flutter analyze
      - run: flutter test
A minimal workflow (.github/workflows/ci.yml). Check the actions' current versions before using.
Think of it like this: Integration tests are like a full dress rehearsal of a wedding: everyone walks through the whole event in order, start to finish. They take time, so you do a few; unit and widget tests are the many small checks (the caterer tasting, the sound check) done every day.

Common mistakes

  • Trying to cover everything with integration tests: slow and flaky suites that nobody runs.
  • Integration tests that depend on live production servers or real payments.
  • Ignoring analyzer warnings until there are hundreds.
  • No CI, so tests are only run "when someone remembers".

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Integration tests and CI · 1/6

Unit > Widget > Integration

The testing pyramid: many unit tests, some widget tests, a few integration tests.

Prefer a video by a teacher? Find free videos on “flutter integration test integration_test github actions ci flutter analyze” on YouTube ↗

In real life: A safety net for a growing team

A three-person team building a tuition-booking app adds CI: every pull request runs dart format check, flutter analyze and 180 unit and widget tests in about four minutes. Two integration tests (sign up, book a class) run nightly on an emulator. When a new developer accidentally breaks the booking time calculation, CI fails on their pull request before it reaches users.

Practice (0/3 done)

Task 1 · Question

Which test type is slowest but checks a complete user journey on a device?

Task 2 · Question

Which command checks code for errors and lint issues without running the app?

Task 3 · Practice

Add one integration test that launches your app, logs in with a test account (or skips login with a fake), performs one key action and checks the result. Then add a GitHub Actions workflow that runs dart format check, flutter analyze and flutter test on every push, and push a commit to see it run.

Quick quiz

Question 1

1.Which binding must integration tests initialise?

Question 2

2.What does dart format --set-exit-if-changed do in CI?

Question 3

3.What should integration tests use for login and payments?

Question 4

4.What is CI?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which binding must integration tests initialise?

Answer: IntegrationTestWidgetsFlutterBinding

Call ensureInitialized() first.

What does dart format --set-exit-if-changed do in CI?

Answer: Fails the job if any file is not formatted

Enforces consistent style.

What should integration tests use for login and payments?

Answer: Test accounts and a test or fake backend

Never use real money or data.

What is CI?

Answer: Automatic checks (analysis, tests) on every code change

Continuous integration.

What does an integration test check that a unit test does not?Related

Answer: That several parts, like handler and database, work together

Integration tests check the joins between parts, where many real bugs live.

From Integration testing: checking parts work together

What does an integration test of POST /api/notes usually use?Related

Answer: The real handler and a separate test database

Integration tests check that the pieces work together (route, validation, SQL) but against a throwaway test database.

From Testing a full-stack app

In the test pyramid, which kind of test should you have the most of?Related

Answer: Unit

Unit tests are fast and cheap, so you can have many. E2E tests are slower, so keep a few for key journeys.

From Testing basics: unit, integration and end-to-end

What does the test pyramid recommend?Related

Answer: Mostly unit tests, fewer integration tests, few UI tests

Fast, focused tests form the base.

From Testing basics and the test pyramid

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Responsive design and testing”. The module exam comes next.
  2. Module 10 exam: Responsive design and testing · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Publishing to the stores and the web. 50 topics left in the course before the final exam.

← Previous: Widget tests