SkillByAIOpen interactive version →

Lesson 22 / 25

Unit, Widget and Integration Tests

The Flutter testing pyramid.

Three kinds of tests

Unit tests check plain Dart logic (models, parsers, notifiers) with test and expect. Widget tests (package flutter_test) render widgets in a fast headless environment: testWidgets gives a WidgetTester to pumpWidget, find widgets with find.text, find.byType or find.byKey, interact with tap and enterText, then call pump() (one frame) or pumpAndSettle() (until animations finish) before asserting with matchers such as findsOneWidget. Integration tests (package integration_test) run the whole app on a real device or emulator. Run tests with flutter test; fake network and storage dependencies with mocks (mocktail or mockito) or provider overrides.

Ship with confidence

Tests catch regressions, profiling keeps frames smooth, and a repeatable build pipeline gets the app to the stores.

Figure 8.1 — Test, profile, build, release.

A widget test for the counter

Pump, tap, pump, expect.

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/counter.dart';

void main() {
  test('Cart adds items', () {
    final cart = Cart();
    cart.add(const Item('Tea'));
    expect(cart.count, 1);
  });

  testWidgets('tapping + increments the counter', (tester) async {
    await tester.pumpWidget(const MaterialApp(home: Scaffold(body: Counter())));

    expect(find.text('Count: 0'), findsOneWidget);

    await tester.tap(find.byIcon(Icons.add));
    await tester.pump(); // rebuild after setState

    expect(find.text('Count: 1'), findsOneWidget);
  });
}

Golden tests for visuals

matchesGoldenFile compares a widget's rendering with a stored image; regenerate goldens with flutter test --update-goldens when a change is intentional.

Quick check: In a widget test, what must you call after tapping a button that calls setState?

  • Nothing; the UI updates instantly
  • flutter run
  • tester.dispose()
  • tester.pump() to build the next frame
Answer

tester.pump() to build the next frame — The test environment only rebuilds when you pump frames.