Skip to content

Flutter Testing

Ce guide couvre les différents types de tests disponibles en Flutter, des tests unitaires aux tests d’intégration, en passant par les mocks et les tests de rendu.

Flutter offre un écosystème complet pour tester vos applications à différents niveaux :

  • Tests unitaires : pour tester la logique métier
  • Tests de widgets : pour tester l’interface utilisateur
  • Tests d’intégration : pour tester l’application complète
  • Tests de couverture : pour mesurer la qualité des tests
  • Golden tests : pour tester le rendu visuel

Flutter intègre directement le support des tests avec le package flutter_test qui étend le package Dart test.

import 'package:test/test.dart';
void main() {
test('String.split() splits the string on the delimiter', () {
var string = 'foo,bar,baz';
expect(string.split(','), ['foo', 'bar', 'baz']);
});
test('String.trim() removes surrounding whitespace', () {
var string = ' foo ';
expect(string.trim(), 'foo');
});
}

Le mocking permet de simuler des dépendances externes pour isoler le code testé.

Il existe deux principales librairies de mocking :

La plus ancienne, développée chez Google. Depuis le passage au null safety, elle est moins pratique à utiliser et nécessite de la génération de code.

Développé par le créateur du package Bloc, reprend les principes de Mockito en les préservant dans une version null safe plus pratique.

class MockBookService extends Mock implements BookService {}
final service = MockService();
// Définir le comportement quand la méthode [service.loadAll] est appelée
when(() => service.loadAll())
.thenAnswer((_) => Future.value([fakeBook1, fakeBook2]));
// Définir le comportement pour [service.loadBook] avec n'importe quel ID
when(() => service.loadBook(id: any(named: 'id')))
.thenAnswer((_) => Future.value(fakeBook));
verify(() => service.loadBook(id: any(named: 'id'))).called(1);

WidgetTester permet de manipuler “virtuellement” un widget afin de vérifier son comportement dans un environnement de test.

Avec ce widget, il est possible de :

  • Rechercher des widgets enfants (voir documentation) :

    • find.text()
    • find.byKey()
    • find.byType()
    • find.byIcon()
    • find.widgetWithIcon()
    • Et bien d’autres…
  • Interagir avec l’interface :

    • tester.tap(...) pour toucher des boutons
    • tester.enterText(...) pour saisir du texte
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
final TestWidgetsFlutterBinding binding =
TestWidgetsFlutterBinding.ensureInitialized();
await binding.setSurfaceSize(const Size(420, 720));
// Construire l'application et déclencher un frame
await tester.pumpWidget(const MyApp());
// Vérifier que le compteur commence à 0
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Appuyer sur l'icône '+' et déclencher un frame
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Vérifier que le compteur a été incrémenté
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}

Flutter permet de générer des informations de couverture de test pour mesurer quelle partie de votre code est testée.

En ligne de commande :

Terminal window
flutter test --coverage

Dans IntelliJ/Android Studio : Utiliser l’option “Run … with Coverage”

Un fichier lcov.info est créé dans ./coverage/lcov.info.

Pour lire ce fichier et générer un rapport HTML :

  1. Installer genhtml

  2. Générer le rapport :

Terminal window
genhtml coverage/lcov.info -o coverage
open coverage/index.html

Le rapport généré ressemble à ceci :

Coverage info example

Les golden tests permettent de tester le rendu graphique de widgets à partir d’images de référence. Ils sont particulièrement utiles pour détecter les changements visuels non intentionnels.

Alchemist est un package qui simplifie la création de golden tests.

Alchemist golden tests

  • Détection automatique des régressions visuelles
  • Validation du rendu sur différentes plateformes
  • Documentation visuelle du comportement attendu

Les tests d’intégration permettent de tester l’application de manière “globale”, en simulant les interactions utilisateur réelles.

Flutter SDK intègre un package integration_test :

dev_dependencies:
integration_test:
sdk: flutter

Les tests d’intégration permettent de :

  • Tester les flux utilisateur complets
  • Valider l’intégration entre les différentes parties de l’application
  • Tester sur de vrais appareils ou émulateurs

Consultez la documentation officielle pour plus de détails.

L’utilisation de setState rend difficile la séparation Vue/Logique et par conséquent la testabilité. Privilégiez les patterns de state management comme Provider, Bloc, ou Riverpod.

  • Organisez vos tests en groupes logiques
  • Nommez clairement vos tests pour décrire le comportement testé
  • Utilisez des setup et teardown appropriés
  • Visez une couverture élevée mais sensée
  • Concentrez-vous sur la logique métier critique
  • N’oubliez pas les cas d’erreur et les edge cases
  • Mockez uniquement les dépendances externes
  • Préférez les vrais objets quand c’est possible
  • Validez les interactions importantes avec vos mocks
  • Testez le comportement utilisateur, pas l’implémentation
  • Utilisez des keys pour identifier les widgets critiques
  • Testez les différents états de vos widgets