Testing
Four kinds of test, one pyramid
Section titled “Four kinds of test, one pyramid”Flutter gives you four testing tools, and they trade speed for realism. Use many fast ones and few slow ones.
flowchart TB integ["Integration tests (whole app, real device) — few, slow"] --> widget["Widget tests (one widget tree, no device) — many, fast"] widget --> unit["Unit tests (pure Dart logic) — most, fastest"]
- Unit tests verify pure Dart — a function, a class, a Cubit’s logic. No UI, no device, milliseconds each.
- Widget tests pump a widget into a test harness and interact with it (tap, enter text, expect) — no real device, still fast. This is the Flutter-specific sweet spot.
- Integration tests run the whole app on a real device or emulator, driving it end to end — slow, but the most realistic.
- Golden tests capture a widget’s rendered pixels and compare against a saved reference image, catching visual regressions.
A unit test
Section titled “A unit test”import 'package:test/test.dart';
test('cart total sums item prices', () { final cart = Cart()..add(Item(price: 10))..add(Item(price: 5)); expect(cart.total, 15);});Plain Dart, plain expect. Most of your logic — pricing, validation, parsing, state transitions — should be reachable by tests this simple, which is a good reason to keep logic out of widgets.
A widget test
Section titled “A widget test”Widget tests use WidgetTester to build a widget, find elements, act, and assert — all in memory.
import 'package:flutter/material.dart';import 'package:flutter_test/flutter_test.dart';
testWidgets('tapping + increments the counter', (WidgetTester tester) async { await tester.pumpWidget(const MyApp()); // build the widget tree
expect(find.text('0'), findsOneWidget); // initial state
await tester.tap(find.byIcon(Icons.add)); // interact await tester.pump(); // rebuild after setState
expect(find.text('1'), findsOneWidget); // assert the new state});The key calls: pumpWidget builds the tree, find locates widgets, tap/enterText interact, and pump (or pumpAndSettle for animations) advances frames so rebuilds happen. No emulator needed — this runs in seconds.
Golden tests
Section titled “Golden tests”testWidgets('button matches golden', (tester) async { await tester.pumpWidget(const MyButton()); await expectLater( find.byType(MyButton), matchesGoldenFile('goldens/my_button.png'), );});Golden (snapshot) tests are powerful for design systems, but brittle across platforms and font versions — pin them carefully and regenerate deliberately with --update-goldens.