Skip to content
AgileLogics
6 min read

Testing Flutter Apps

Prerequisites: Testing with package:test, Navigation and app architecture

Flutter supports three kinds of tests, from fast and narrow to slow and broad:

Kind Tests Speed
Unit tests A function, class, or ViewModel Very fast
Widget tests One widget or screen, without a device Fast
Integration tests The whole app on a device or emulator Slow

Most of your tests should be unit and widget tests.

Unit testing a ViewModel with a fake

import 'package:flutter_test/flutter_test.dart';

class FakeArticleRepository implements ArticleRepository {
  FakeArticleRepository({this.fail = false});
  final bool fail;

  @override
  Future<List<Article>> latest() async {
    if (fail) throw Exception('offline');
    return const [Article(1, 'Hello')];
  }
}

void main() {
  test('loads articles', () async {
    final vm = ArticlesViewModel(FakeArticleRepository());
    await vm.load();
    expect(vm.articles, hasLength(1));
    expect(vm.error, isNull);
  });

  test('shows an error when loading fails', () async {
    final vm = ArticlesViewModel(FakeArticleRepository(fail: true));
    await vm.load();
    expect(vm.error, isNotNull);
  });
}

Widget tests

A widget test builds a widget in a test environment and interacts with it:

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

void main() {
  testWidgets('tapping the button increments the counter', (tester) async {
    await tester.pumpWidget(const MaterialApp(home: CounterPage()));

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

    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();

    expect(find.text('Count: 1'), findsOneWidget);
  });
}
  • pumpWidget builds the widget; pump renders the next frame after a change (pumpAndSettle waits for animations to finish).
  • Finders locate widgets: find.text, find.byIcon, find.byType, find.byKey.
  • Run them with flutter test — no device needed.

Integration tests

The integration_test package drives the real app on a device or emulator — use it for a handful of critical journeys, such as sign-up and checkout.

Mocks

For verifying interactions ("was save called once?"), the mocktail or mockito packages create mock objects. Hand-written fakes like the one above are often simpler and clearer.