This episode builds confidence in your code: unit testing Dart logic with flutter_test, widget testing and golden tests, integration testing with flutter_test and flutter drive, and continuous testing and test automation to keep quality high on every change.

An app that grows without tests is a time bomb: one small change can break an unexpected feature. Episode 13 builds a safety layer through structured testing — from the smallest unit tests to integration tests that run a real app.
We discuss unit testing Dart logic, widget testing and golden tests, integration testing with flutter_test and flutter drive, and continuous testing and test automation strategies.
Unit tests verify pure logic — models, repositories, calculations — without UI. All Flutter tests use the flutter_test package:
import 'package:flutter_test/flutter_test.dart';
int tambah(int a, int b) => a + b;
void main() {
test('menjumlahkan dua angka', () {
expect(tambah(2, 3), 5);
});
}test defines a test case and expect verifies the result. This structure is the foundation of the entire test suite — everything uses the test and expect pattern.
For many tests, use group to keep output organized:
group('Calculator', () {
test('mengembalikan 5 untuk 2 + 3', () {
expect(tambah(2, 3), 5);
});
test('mengembalikan 0 untuk angka negatif seimbang', () {
expect(tambah(-1, 1), 0);
});
});group wraps several tests into one category. Run all tests with:
flutter testflutter test runs every _test.dart file in the test/ folder. Every change to business logic should come with an updated test.
Widget tests run the UI in a simulated environment without a device:
testWidgets('menampilkan nilai awal', (tester) async {
await tester.pumpWidget(const MaterialApp(home: CounterScreen()));
expect(find.text('Nilai: 0'), findsOneWidget);
await tester.tap(find.byType(FloatingActionButton));
await tester.pump();
expect(find.text('Nilai: 1'), findsOneWidget);
});tester.pumpWidget mounts the widget, tester.tap simulates a tap, and tester.pump() processes the rebuild. findsOneWidget verifies the presence of the widget being sought.
A golden test compares a widget's render against a reference image (snapshot):
testWidgets('sesuai golden', (tester) async {
await tester.pumpWidget(const MaterialApp(home: HomeScreen()));
await expectLater(
find.byType(HomeScreen),
matchesGoldenFile('goldens/home.png'),
);
});matchesGoldenFile('goldens/home.png') compares the view against the reference file. When a design legitimately changes, update the golden by running the test with the --update-goldens flag. Golden tests make sure even the smallest invisible change doesn't slip through.
Integration tests run the app on a device or emulator and test end-to-end flows:
dev_dependencies:
flutter_test:
sdk: flutter
integration_test:
sdk: flutterAdd integration_test from the SDK to dev_dependencies. Tests are written in the integration_test/ folder:
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('login berhasil', (tester) async {
app.main();
await tester.pumpAndSettle();
await tester.enterText(find.byKey(const Key('email')), 'user@example.com');
await tester.tap(find.byKey(const Key('login_button')));
await tester.pumpAndSettle();
expect(find.text('Selamat datang'), findsOneWidget);
});app.main() runs the real app, and pumpAndSettle() waits for all animations to finish. find.byKey uses a Key defined in the widget — an important reason to give Keys to key interactive elements.
Run integration tests on a device:
flutter test integration_test -d linuxflutter test integration_test -d linux runs the entire integration test folder on the specified device. The -d target can be an emulator, physical device, or desktop.
Run the test suite in CI before merging:
flutter analyze && flutter testflutter analyze && flutter test combines static analysis and the full test suite. This pattern must exist in the CI pipeline — in this series, the release flow in episode 14 and the runbooks in episode 19 will build on the same foundation.
flutter test --coverage produces a coverage report. A realistic target isn't absolute 100 percent, but covering critical logic: validation, auth, and payments. Prioritize tests that catch high-cost regressions.
Key takeaways:
test and expect.flutter test runs the whole suite in the test/ folder.flutter_test and integration_test.flutter analyze && flutter test in CI.In the next episode 14 we discuss deployment and release management — building release app bundles for Android and iOS, code signing, provisioning profiles, and app store submission, web deployment and desktop packaging, and release channels and versioning. Your app is ready to be shipped to users.