Tests Flutter
Cette section présentera trois types de tests dans Flutter : les tests unitaires, les tests de widgets et les tests d'intégration.
Aperçu des types de tests
| Type | Description | Exécuter des commandes |
|---|---|---|
| Tests unitaires | Tester des fonctions individuelles et des méthodes de classe | flutter test |
| Tests de widgets | Tester l'interface utilisateur d'un seul Widget | flutter test |
| Tests d’intégration | Tester le flux complet de l'application | flutter test integration_test/ |
Tests unitaires
Les tests unitaires servent à tester le code de la logique métier.
Exemple : Exemple de test unitaire
// math_utils.dart - code à tester
class MathUtils {
static int add(int a, int b) => a + b;
static int subtract(int a, int b) => a - b;
static int multiply(int a, int b) => a * b;
static double divide(int a, int b) {
if (b == 0) throw ArgumentError(Impossible de diviser par zéro);
return a / b;
}
static int factorial(int n) {
if (n < 0) throw ArgumentError(Les nombres négatifs n'ont pas de factorielle);
if (n == 0 || n == 1) return 1;
return n * factorial(n - 1);
}
}
// math_utils_test.dart - fichier de test
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/math_utils.dart';
void main() {
group('MathUtils', () {
test(add additionne deux nombres, () {
expect(MathUtils.add(2, 3), equals(5));
});
test(subtract soustrait deux nombres, () {
expect(MathUtils.subtract(5, 3), equals(2));
});
test(multiply multiplie deux nombres, () {
expect(MathUtils.multiply(4, 5), equals(20));
});
test(divide divise deux nombres, () {
expect(MathUtils.divide(10, 2), equals(5));
});
test(divide lève une exception lors d'une division par zéro, () {
expect(() => MathUtils.divide(10, 0), throwsArgumentError);
});
test(factorial calcule la factorielle, () {
expect(MathUtils.factorial(5), equals(120));
expect(MathUtils.factorial(0), equals(1));
});
test(factorial lève une exception pour les nombres négatifs, () {
expect(() => MathUtils.factorial(-1), throwsArgumentError);
});
});
}
class MathUtils {
static int add(int a, int b) => a + b;
static int subtract(int a, int b) => a - b;
static int multiply(int a, int b) => a * b;
static double divide(int a, int b) {
if (b == 0) throw ArgumentError(Impossible de diviser par zéro);
return a / b;
}
static int factorial(int n) {
if (n < 0) throw ArgumentError(Les nombres négatifs n'ont pas de factorielle);
if (n == 0 || n == 1) return 1;
return n * factorial(n - 1);
}
}
// math_utils_test.dart - fichier de test
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/math_utils.dart';
void main() {
group('MathUtils', () {
test(add additionne deux nombres, () {
expect(MathUtils.add(2, 3), equals(5));
});
test(subtract soustrait deux nombres, () {
expect(MathUtils.subtract(5, 3), equals(2));
});
test(multiply multiplie deux nombres, () {
expect(MathUtils.multiply(4, 5), equals(20));
});
test(divide divise deux nombres, () {
expect(MathUtils.divide(10, 2), equals(5));
});
test(divide lève une exception lors d'une division par zéro, () {
expect(() => MathUtils.divide(10, 0), throwsArgumentError);
});
test(factorial calcule la factorielle, () {
expect(MathUtils.factorial(5), equals(120));
expect(MathUtils.factorial(0), equals(1));
});
test(factorial lève une exception pour les nombres négatifs, () {
expect(() => MathUtils.factorial(-1), throwsArgumentError);
});
});
}
Tests de widgets
Les tests de widgets sont utilisés pour tester les composants d'interface utilisateur.
Exemple : test de widget
// counter_widget.dart - Widget en cours de test
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(Nombre : $_count, key: const Key('counter_text')),
ElevatedButton(
key: const Key('increment_button'),
onPressed: _increment,
child: const Text('Increase'),
),
],
);
}
}
// counter_widget_test.dart - fichier de test
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/counter_widget.dart';
void main() {
testWidgets(CounterWidget affiche le nombre initial, (WidgetTester tester) async {
// Construire le widget
await tester.pumpWidget(const MaterialApp(
home: CounterWidget(),
));
// Vérifier l'affichage du nombre initial
expect(find.text(Count: 0), findsOneWidget);
});
testWidgets(CounterWidget incrémente le nombre lors du clic sur le bouton, (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: CounterWidget(),
));
// Trouver et cliquer sur le bouton
await tester.tap(find.byKey(const Key('increment_button')));
await tester.pump();
// Vérifier que le compteur a été mis à jour
expect(find.text(Count: 1), findsOneWidget);
// Cliquer à nouveau
await tester.tap(find.byKey(const Key('increment_button')));
await tester.pump();
expect(find.text(Count: 2), findsOneWidget);
});
}
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(Nombre : $_count, key: const Key('counter_text')),
ElevatedButton(
key: const Key('increment_button'),
onPressed: _increment,
child: const Text('Increase'),
),
],
);
}
}
// counter_widget_test.dart - fichier de test
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/counter_widget.dart';
void main() {
testWidgets(CounterWidget affiche le nombre initial, (WidgetTester tester) async {
// Construire le widget
await tester.pumpWidget(const MaterialApp(
home: CounterWidget(),
));
// Vérifier l'affichage du nombre initial
expect(find.text(Count: 0), findsOneWidget);
});
testWidgets(CounterWidget incrémente le nombre lors du clic sur le bouton, (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: CounterWidget(),
));
// Trouver et cliquer sur le bouton
await tester.tap(find.byKey(const Key('increment_button')));
await tester.pump();
// Vérifier que le compteur a été mis à jour
expect(find.text(Count: 1), findsOneWidget);
// Cliquer à nouveau
await tester.tap(find.byKey(const Key('increment_button')));
await tester.pump();
expect(find.text(Count: 2), findsOneWidget);
});
}
Tests d’intégration
Les tests d'intégration servent à tester le flux complet des fonctionnalités de l'application.
Exemple : test d'intégration
// integration_test/app_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group(App integration test, () {
testWidgets(Test complet du parcours utilisateur, (WidgetTester tester) async {
// Lancer l'application
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
// Vérifier que la page d'accueil est affichée
expect(find.text('Accueil'), findsOneWidget);
// Cliquer pour naviguer vers la page de détail
await tester.tap(find.text('Détails'));
await tester.pumpAndSettle();
// Vérifier l'affichage de la page de détail
expect(find.text('Page de détail'), findsOneWidget);
// Cliquer sur retour
await tester.tap(find.byIcon(Icons.arrow_back));
await tester.pumpAndSettle();
// Vérifier le retour à l'accueil
expect(find.text('Accueil'), findsOneWidget);
});
});
}
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group(App integration test, () {
testWidgets(Test complet du parcours utilisateur, (WidgetTester tester) async {
// Lancer l'application
await tester.pumpWidget(const MyApp());
await tester.pumpAndSettle();
// Vérifier que la page d'accueil est affichée
expect(find.text('Accueil'), findsOneWidget);
// Cliquer pour naviguer vers la page de détail
await tester.tap(find.text('Détails'));
await tester.pumpAndSettle();
// Vérifier l'affichage de la page de détail
expect(find.text('Page de détail'), findsOneWidget);
// Cliquer sur retour
await tester.tap(find.byIcon(Icons.arrow_back));
await tester.pumpAndSettle();
// Vérifier le retour à l'accueil
expect(find.text('Accueil'), findsOneWidget);
});
});
}
autres extensionsUne bonne couverture de tests peut améliorer la qualité du code ; il est recommandé d'écrire des tests unitaires pour au moins la logique métier principale.