1. Einführung
Flutter ist das UI-Toolkit von Google, mit dem Sie mit einer einzigen Codebasis ansprechende, nativ kompilierte Apps für Mobilgeräte, Web und Desktop erstellen können.
In diesem Codelab erstellen und testen Sie eine einfache Flutter-App. Die App verwendet das Paket Provider zur Verwaltung des Status.
Lerninhalte
- Widget-Tests mit dem Widget-Test-Framework erstellen
- Wie du einen Integrationstest erstellst, um die UI und Leistung der App mit der
integration_test
-Bibliothek zu testen - So testen Sie Datenklassen (Anbieter) mithilfe von Einheitentests
Aufgaben
In diesem Codelab erstellen Sie zuerst eine einfache Anwendung mit einer Liste von Elementen. Wir stellen Ihnen den Quellcode zur Verfügung, damit Sie direkt mit den Tests beginnen können. Die Anwendung unterstützt die folgenden Vorgänge:
- Hinzufügen der Artikel zu Favoriten
- Anzeigen der Favoritenliste
- Elemente werden aus der Favoritenliste entfernt
Sobald die Anwendung fertig ist, schreiben Sie die folgenden Tests:
| GIF der Android-App |
Was möchten Sie in diesem Codelab lernen?
<ph type="x-smartling-placeholder">2. Flutter-Entwicklungsumgebung einrichten
Für dieses Lab benötigen Sie zwei Softwareprogramme: das Flutter SDK und einen Editor.
Sie können das Codelab auf jedem dieser Geräte ausführen:
- Ein physisches Android- oder iOS, das mit Ihrem Computer verbunden ist und sich im Entwicklermodus befindet.
- Den iOS-Simulator (erfordert die Installation von Xcode-Tools).
- Android-Emulator (Einrichtung in Android Studio erforderlich)
- Ein Browser (zur Fehlerbehebung wird Chrome benötigt)
- Als Windows-, Linux- oder macOS-Desktopanwendung Die Entwicklung muss auf der Plattform erfolgen, auf der Sie die Bereitstellung planen. Wenn Sie also eine Windows-Desktop-App entwickeln möchten, müssen Sie die Entwicklung unter Windows ausführen, damit Sie auf die entsprechende Build-Kette zugreifen können. Es gibt betriebssystemspezifische Anforderungen, die unter docs.flutter.dev/desktop ausführlich beschrieben werden.
3. Erste Schritte
Neue Flutter-App erstellen und Abhängigkeiten aktualisieren
In diesem Codelab geht es um das Testen einer mobilen Flutter-App. Sie erstellen die zu testende Anwendung schnell mit Quelldateien, die Sie kopieren und einfügen. Im restlichen Codelab lernen Sie dann verschiedene Arten von Tests kennen.
Erstellen Sie eine einfache, aus Vorlagen erstellte Flutter-App. Folgen Sie dazu entweder der Anleitung unter Erste Schritte mit Ihrer ersten Flutter-App oder folgen Sie der Anleitung in der Befehlszeile.
$ flutter create --empty testing_app Creating project testing_app... Resolving dependencies in `testing_app`... Downloading packages... Got dependencies in `testing_app`. Wrote 128 files. All done! You can find general documentation for Flutter at: https://docs.flutter.dev/ Detailed API documentation is available at: https://api.flutter.dev/ If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev In order to run your empty application, type: $ cd testing_app $ flutter run Your empty application code is in testing_app/lib/main.dart.
Pub-Abhängigkeiten in der Befehlszeile hinzufügen
provider
für eine einfache Statusverwaltung,integration_test
zum selbstfahrenden Testen von Flutter-Code auf Geräten und Emulatorenflutter_driver
für eine erweiterte API zum Testen von Flutter-Anwendungen, die auf echten Geräten und Emulatoren ausgeführt werden,test
für allgemeine Testtoolsgo_router
für die App-Navigation
$ cd testing_app $ flutter pub add provider go_router dev:test 'dev:flutter_driver:{"sdk":"flutter"}' 'dev:integration_test:{"sdk":"flutter"}' Resolving dependencies... Downloading packages... + _fe_analyzer_shared 67.0.0 (68.0.0 available) + analyzer 6.4.1 (6.5.0 available) + args 2.5.0 + convert 3.1.1 + coverage 1.7.2 + crypto 3.0.3 + file 7.0.0 + flutter_driver 0.0.0 from sdk flutter + flutter_web_plugins 0.0.0 from sdk flutter + frontend_server_client 4.0.0 + fuchsia_remote_debug_protocol 0.0.0 from sdk flutter + glob 2.1.2 + go_router 14.0.2 + http_multi_server 3.2.1 + http_parser 4.0.2 + integration_test 0.0.0 from sdk flutter + io 1.0.4 + js 0.7.1 leak_tracker 10.0.4 (10.0.5 available) leak_tracker_flutter_testing 3.0.3 (3.0.5 available) + logging 1.2.0 material_color_utilities 0.8.0 (0.11.1 available) meta 1.12.0 (1.14.0 available) + mime 1.0.5 + nested 1.0.0 + node_preamble 2.0.2 + package_config 2.1.0 + platform 3.1.4 + pool 1.5.1 + process 5.0.2 + provider 6.1.2 + pub_semver 2.1.4 + shelf 1.4.1 + shelf_packages_handler 3.0.2 + shelf_static 1.1.2 + shelf_web_socket 1.0.4 + source_map_stack_trace 2.1.1 + source_maps 0.10.12 + sync_http 0.3.1 + test 1.25.2 (1.25.4 available) test_api 0.7.0 (0.7.1 available) + test_core 0.6.0 (0.6.2 available) + typed_data 1.3.2 + watcher 1.1.0 + web 0.5.1 + web_socket_channel 2.4.5 + webdriver 3.0.3 + webkit_inspection_protocol 1.2.1 + yaml 3.1.2 Changed 44 dependencies! 9 packages have newer versions incompatible with dependency constraints. Try `flutter pub outdated` for more information.
Die folgenden Abhängigkeiten sollten Ihrer pubspec.yaml hinzugefügt worden sein:
pubspec.yaml
name: testing_app description: "A new Flutter project." publish_to: 'none' version: 0.1.0 environment: sdk: '>=3.4.0-0 <4.0.0' dependencies: flutter: sdk: flutter go_router: ^14.0.2 provider: ^6.1.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.0 test: ^1.25.2 flutter_driver: sdk: flutter integration_test: sdk: flutter flutter: uses-material-design: true
Öffnen Sie das Projekt in einem Codeeditor Ihrer Wahl und führen Sie die App aus. Alternativ können Sie ihn wie folgt in der Befehlszeile ausführen.
$ flutter run
4. App erstellen
Als Nächstes erstellen Sie die App, um sie zu testen. Die Anwendung enthält die folgenden Dateien:
lib/models/favorites.dart
– erstellt die Modellklasse für die Favoritenlistelib/screens/favorites.dart
erstellt das Layout für die Favoritenliste.lib/screens/home.dart
: Erstellt eine Liste von Elementenlib/main.dart
– die Hauptdatei, in der die Anwendung gestartet wird
Erstellen Sie zuerst das Modell Favorites
in lib/models/favorites.dart
Erstellen Sie im Verzeichnis lib
ein neues Verzeichnis mit dem Namen models
und erstellen Sie dann eine neue Datei mit dem Namen favorites.dart
. Fügen Sie in diese Datei den folgenden Code ein:
lib/models/favorites.dart
import 'package:flutter/material.dart';
/// The [Favorites] class holds a list of favorite items saved by the user.
class Favorites extends ChangeNotifier {
final List<int> _favoriteItems = [];
List<int> get items => _favoriteItems;
void add(int itemNo) {
_favoriteItems.add(itemNo);
notifyListeners();
}
void remove(int itemNo) {
_favoriteItems.remove(itemNo);
notifyListeners();
}
}
Fügen Sie die Favoritenseite in lib/screens/favorites.dart
hinzu
Erstellen Sie im Verzeichnis lib
ein neues Verzeichnis mit dem Namen screens
und dort eine neue Datei mit dem Namen favorites.dart
. Fügen Sie in diese Datei den folgenden Code ein:
lib/screens/favorites.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/favorites.dart';
class FavoritesPage extends StatelessWidget {
const FavoritesPage({super.key});
static String routeName = 'favorites_page';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Favorites'),
),
body: Consumer<Favorites>(
builder: (context, value, child) => ListView.builder(
itemCount: value.items.length,
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (context, index) => FavoriteItemTile(value.items[index]),
),
),
);
}
}
class FavoriteItemTile extends StatelessWidget {
const FavoriteItemTile(this.itemNo, {super.key});
final int itemNo;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
),
title: Text(
'Item $itemNo',
key: Key('favorites_text_$itemNo'),
),
trailing: IconButton(
key: Key('remove_icon_$itemNo'),
icon: const Icon(Icons.close),
onPressed: () {
Provider.of<Favorites>(context, listen: false).remove(itemNo);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Removed from favorites.'),
duration: Duration(seconds: 1),
),
);
},
),
),
);
}
}
Startseite in lib/screens/home.dart
hinzufügen
Erstellen Sie im Verzeichnis lib/screens
eine weitere neue Datei mit dem Namen home.dart
. Fügen Sie in lib/screens/home.dart
den folgenden Code ein:
lib/screens/home.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import '../models/favorites.dart';
import 'favorites.dart';
class HomePage extends StatelessWidget {
static String routeName = '/';
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Testing Sample'),
actions: <Widget>[
TextButton.icon(
onPressed: () {
context.go('/${FavoritesPage.routeName}');
},
icon: const Icon(Icons.favorite_border),
label: const Text('Favorites'),
),
],
),
body: ListView.builder(
itemCount: 100,
cacheExtent: 20.0,
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (context, index) => ItemTile(index),
),
);
}
}
class ItemTile extends StatelessWidget {
final int itemNo;
const ItemTile(this.itemNo, {super.key});
@override
Widget build(BuildContext context) {
var favoritesList = Provider.of<Favorites>(context);
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
),
title: Text(
'Item $itemNo',
key: Key('text_$itemNo'),
),
trailing: IconButton(
key: Key('icon_$itemNo'),
icon: favoritesList.items.contains(itemNo)
? const Icon(Icons.favorite)
: const Icon(Icons.favorite_border),
onPressed: () {
!favoritesList.items.contains(itemNo)
? favoritesList.add(itemNo)
: favoritesList.remove(itemNo);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(favoritesList.items.contains(itemNo)
? 'Added to favorites.'
: 'Removed from favorites.'),
duration: const Duration(seconds: 1),
),
);
},
),
),
);
}
}
Inhalt von lib/main.dart
ersetzen
Ersetzen Sie den Inhalt von lib/main.dart
durch den folgenden Code:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'models/favorites.dart';
import 'screens/favorites.dart';
import 'screens/home.dart';
void main() {
runApp(const TestingApp());
}
final _router = GoRouter(
routes: [
GoRoute(
path: HomePage.routeName,
builder: (context, state) {
return const HomePage();
},
routes: [
GoRoute(
path: FavoritesPage.routeName,
builder: (context, state) {
return const FavoritesPage();
},
),
],
),
],
);
class TestingApp extends StatelessWidget {
const TestingApp({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Favorites>(
create: (context) => Favorites(),
child: MaterialApp.router(
title: 'Testing Sample',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepPurple,
),
useMaterial3: true,
),
routerConfig: _router,
),
);
}
}
Die Anwendung ist jetzt vollständig, wurde aber noch nicht getestet.
App ausführen Er sollte so aussehen:
Die App zeigt eine Liste mit Artikeln an. Tippe in einer beliebigen Zeile auf das herzförmige Symbol, um das Herz zu füllen und den Artikel deiner Favoritenliste hinzuzufügen. Über die Schaltfläche Favoriten auf dem AppBar
gelangst du zu einem zweiten Bildschirm mit der Favoritenliste.
Die App kann jetzt getestet werden. Im nächsten Schritt beginnen Sie mit dem Testen der App.
5. Unittest des Anbieters
Sie beginnen mit einem Einheitentest des favorites
-Modells. Was ist ein Unittest? Ein Unittest überprüft, ob jede einzelne Softwareeinheit, ob eine Funktion, ein Objekt oder ein Widget, die beabsichtigte Aufgabe ordnungsgemäß ausführt.
Alle Testdateien in einer Flutter-Anwendung, mit Ausnahme von Integrationstests, werden im Verzeichnis test
abgelegt.
test/widget_test.dart
entfernen
Löschen Sie die Datei widget_test.dart
, bevor Sie mit dem Testen beginnen. Sie fügen Ihre eigenen Testdateien hinzu.
Neue Testdatei erstellen
Zuerst testen Sie die Methode add()
im Modell Favorites
, um zu prüfen, ob der Liste ein neues Element hinzugefügt wird und ob die Änderung in der Liste berücksichtigt wird. Konventionsgemäß entspricht die Verzeichnisstruktur im Verzeichnis test
der im Verzeichnis lib
und in den Dart-Dateien, die denselben Namen haben, wobei _test
angehängt ist.
Erstellen Sie im Verzeichnis test
ein Verzeichnis models
. Erstellen Sie in diesem neuen Verzeichnis eine favorites_test.dart
-Datei mit folgendem Inhalt:
test/models/favorites_test.dart
import 'package:test/test.dart';
import 'package:testing_app/models/favorites.dart';
void main() {
group('Testing App Provider', () {
var favorites = Favorites();
test('A new item should be added', () {
var number = 35;
favorites.add(number);
expect(favorites.items.contains(number), true);
});
});
}
Mit dem Flutter-Test-Framework können Sie ähnliche Tests, die zueinander in Beziehung stehen, in einer Gruppe zusammenfassen. Eine Testdatei kann mehrere Gruppen enthalten, mit denen verschiedene Teile der entsprechenden Datei im Verzeichnis lib
getestet werden sollen.
Die Methode test()
verwendet zwei Positionsparameter: den description
des Tests und den callback
, in den Sie den Test schreiben.
Einen Artikel aus der Liste entfernen (Test) Fügen Sie den folgenden Test in dieselbe Testing App Provider
-Gruppe ein:
test/models/favorites_test.dart
test('An item should be removed', () {
var number = 45;
favorites.add(number);
expect(favorites.items.contains(number), true);
favorites.remove(number);
expect(favorites.items.contains(number), false);
});
Test durchführen
Gehen Sie in der Befehlszeile zum Stammverzeichnis des Projekts und geben Sie den folgenden Befehl ein:
$ flutter test test/models/favorites_test.dart
Wenn alles funktioniert, sollten Sie eine Meldung wie diese sehen:
00:06 +2: All tests passed!
Die vollständige Testdatei: test/models/favorites_test.dart
.
Weitere Informationen zu Einheitentests finden Sie in der Einführung in Einheitentests.
6. Widget-Tests
In diesem Schritt fügen Sie Code zum Testen von Widgets hinzu. Widget-Tests gibt es nur bei Flutter. Hier können Sie jedes Widget isoliert testen. In diesem Schritt werden die Bildschirme HomePage
und FavoritesPage
einzeln getestet.
Für Widget-Tests wird die Funktion testWidget()
anstelle der Funktion test()
verwendet. Wie die test()
-Funktion verwendet auch die testWidget()
-Funktion zwei Parameter: description,
und callback
. Der Callback übernimmt jedoch WidgetTester
als Argument.
Widget-Tests verwenden TestFlutterWidgetsBinding
.Diese Klasse stellt für Ihre Widgets dieselben Ressourcen bereit wie in einer laufenden App. Beispiel: Informationen zur Bildschirmgröße und zur Planung von Animationen, die nicht in einer App ausgeführt werden müssen. Stattdessen wird eine virtuelle Umgebung verwendet, um das Widget zu instanziieren und anschließend die Ergebnisse zu testen. Hier startet pumpWidget
den Prozess und weist das Framework an, ein bestimmtes Widget wie in einer Anwendung bereitzustellen und zu messen.
Mit dem Widget-Test-Framework können Finder Widgets finden, z. B. text()
, byType()
und byIcon().
. Das Framework bietet auch Abgleichstools, um die Ergebnisse zu prüfen.
Testen Sie zuerst das HomePage
-Widget.
Neue Testdatei erstellen
Mit dem ersten Test wird überprüft, ob das Scrollen der HomePage
ordnungsgemäß funktioniert.
Erstellen Sie im Verzeichnis test
eine neue Datei und nennen Sie sie home_test.dart
. Fügen Sie der neu erstellten Datei den folgenden Code hinzu:
test/home_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/home.dart';
Widget createHomeScreen() => ChangeNotifierProvider<Favorites>(
create: (context) => Favorites(),
child: const MaterialApp(
home: HomePage(),
),
);
void main() {
group('Home Page Widget Tests', () {
testWidgets('Testing Scrolling', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.text('Item 0'), findsOneWidget);
await tester.fling(
find.byType(ListView),
const Offset(0, -200),
3000,
);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsNothing);
});
});
}
Mit der Funktion createHomeScreen()
wird eine App erstellt, die das zu testende Widget in einer MaterialApp lädt, eingebunden in einen ChangeNotifierProvider. Für das Startseiten-Widget müssen beide Widgets in der Widget-Baumstruktur darüber vorhanden sein, damit es die Widgets übernehmen und Zugriff auf die angebotenen Daten erhalten kann. Diese Funktion wird als Parameter an die Funktion pumpWidget()
übergeben.
Testen Sie als Nächstes, ob das Framework ein auf dem Bildschirm gerendertes ListView
finden kann.
Fügen Sie home_test.dart
das folgende Code-Snippet hinzu:
test/home_test.dart
group('Home Page Widget Tests', () {
// BEGINNING OF NEW CONTENT
testWidgets('Testing if ListView shows up', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.byType(ListView), findsOneWidget);
});
// END OF NEW CONTENT
testWidgets('Testing Scrolling', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.text('Item 0'), findsOneWidget);
await tester.fling(
find.byType(ListView),
const Offset(0, -200),
3000,
);
await tester.pumpAndSettle();
expect(find.text('Item 0'), findsNothing);
});
});
Test durchführen
Führen Sie zunächst den Test auf dieselbe Weise durch wie einen Einheitentest. Verwenden Sie folgenden Befehl:
$ flutter test test/home_test.dart
Der Test sollte schnell ausgeführt werden und Sie sollten eine Meldung wie die folgende sehen:
00:02 +2: All tests passed!
Sie können Widget-Tests auch mit einem Gerät oder einem Emulator ausführen, um den laufenden Test mitzuverfolgen. Sie können auch einen Heißneustart verwenden.
Schließen Sie Ihr Gerät an die Stromversorgung an oder starten Sie den Emulator. Sie können den Test auch als Desktopanwendung ausführen.
Gehen Sie über die Befehlszeile zum Stammverzeichnis des Projekts und geben Sie den folgenden Befehl ein:
$ flutter run test/home_test.dart
Möglicherweise musst du das Gerät auswählen, auf dem der Test ausgeführt werden soll. Folgen Sie in diesem Fall der Anleitung und wählen Sie ein Gerät aus:
Multiple devices found:
Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web) • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"):
Wenn alles funktioniert, sollte die Ausgabe in etwa so aussehen:
Launching test/home_test.dart on Linux in debug mode...
Building Linux application...
flutter: 00:00 +0: Home Page Widget Tests Testing if ListView shows up
Syncing files to device Linux... 62ms
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
💪 Running with sound null safety 💪
An Observatory debugger and profiler on Linux is available at: http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:00 +1: Home Page Widget Tests Testing Scrolling
The Flutter DevTools debugger and profiler on Linux is available at:
http://127.0.0.1:9100?uri=http://127.0.0.1:35583/GCpdLBqf2UI=/
flutter: 00:02 +2: All tests passed!
Als Nächstes nehmen Sie Änderungen an der Testdatei vor und drücken Shift + R
, um die App neu zu starten und alle Tests noch einmal auszuführen. Beenden Sie die Anwendung nicht.
Fügen Sie der Gruppe, die die Startseiten-Widgets testet, weitere Tests hinzu. Kopieren Sie den folgenden Test in Ihre Datei:
test/home_test.dart
testWidgets('Testing IconButtons', (tester) async {
await tester.pumpWidget(createHomeScreen());
expect(find.byIcon(Icons.favorite), findsNothing);
await tester.tap(find.byIcon(Icons.favorite_border).first);
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Added to favorites.'), findsOneWidget);
expect(find.byIcon(Icons.favorite), findsWidgets);
await tester.tap(find.byIcon(Icons.favorite).first);
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Removed from favorites.'), findsOneWidget);
expect(find.byIcon(Icons.favorite), findsNothing);
});
Bei diesem Test wird überprüft, ob sich das Antippen des IconButton
von Icons.favorite_border
(offenes Herz) zu Icons.favorite
(ein ausgefülltes Herz) und dann wieder zurück zu Icons.favorite_border
ändert, wenn es noch einmal angetippt wird.
Geben Sie Shift + R
ein. Dadurch wird die App neu gestartet und alle Tests werden noch einmal ausgeführt.
Die vollständige Testdatei: test/home_test.dart
.
Gehen Sie genauso vor, um die FavoritesPage
mit dem folgenden Code zu testen. Führen Sie dieselben Schritte aus und führen Sie es aus.
test/favorites_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';
late Favorites favoritesList;
Widget createFavoritesScreen() => ChangeNotifierProvider<Favorites>(
create: (context) {
favoritesList = Favorites();
return favoritesList;
},
child: const MaterialApp(
home: FavoritesPage(),
),
);
void addItems() {
for (var i = 0; i < 10; i += 2) {
favoritesList.add(i);
}
}
void main() {
group('Favorites Page Widget Tests', () {
testWidgets('Test if ListView shows up', (tester) async {
await tester.pumpWidget(createFavoritesScreen());
addItems();
await tester.pumpAndSettle();
expect(find.byType(ListView), findsOneWidget);
});
testWidgets('Testing Remove Button', (tester) async {
await tester.pumpWidget(createFavoritesScreen());
addItems();
await tester.pumpAndSettle();
var totalItems = tester.widgetList(find.byIcon(Icons.close)).length;
await tester.tap(find.byIcon(Icons.close).first);
await tester.pumpAndSettle();
expect(tester.widgetList(find.byIcon(Icons.close)).length,
lessThan(totalItems));
expect(find.text('Removed from favorites.'), findsOneWidget);
});
});
}
Dieser Test überprüft, ob ein Element verschwindet, wenn die Schaltfläche zum Schließen (Entfernen) gedrückt wird.
Weitere Informationen zu Widget-Tests finden Sie unter:
7. App-UI mit Integrationstests testen
Integrationstests werden verwendet, um zu testen, wie die einzelnen Teile einer App als Ganzes zusammenarbeiten. Die Bibliothek integration_test
wird verwendet, um Integrationstests in Flutter durchzuführen. Dies ist die Flutter-Version von Selenium WebDriver, Protraktor, Espresso oder Earl Gray. Das Paket verwendet intern flutter_driver
, um den Test auf einem Gerät durchzuführen.
Das Schreiben von Integrationstests in Flutter ähnelt dem Schreiben von Widgettests, mit der Ausnahme, dass Integrationstests auf einem Mobilgerät, in einem Browser oder in einer Desktopanwendung ausgeführt werden, dem Zielgerät.
Test schreiben
Erstellen Sie im Stammverzeichnis des Projekts ein Verzeichnis mit dem Namen integration_test
und dort eine neue Datei mit dem Namen app_test.dart
.
integration_test/app_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:testing_app/main.dart';
void main() {
group('Testing App', () {
testWidgets('Favorites operations test', (tester) async {
await tester.pumpWidget(const TestingApp());
final iconKeys = [
'icon_0',
'icon_1',
'icon_2',
];
for (var icon in iconKeys) {
await tester.tap(find.byKey(ValueKey(icon)));
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Added to favorites.'), findsOneWidget);
}
await tester.tap(find.text('Favorites'));
await tester.pumpAndSettle();
final removeIconKeys = [
'remove_icon_0',
'remove_icon_1',
'remove_icon_2',
];
for (final iconKey in removeIconKeys) {
await tester.tap(find.byKey(ValueKey(iconKey)));
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.text('Removed from favorites.'), findsOneWidget);
}
});
});
}
Test durchführen
Schließen Sie Ihr Gerät an die Stromversorgung an oder starten Sie den Emulator. Sie können den Test auch als Desktopanwendung ausführen.
Gehen Sie in der Befehlszeile zum Stammverzeichnis des Projekts und geben Sie den folgenden Befehl ein:
$ flutter test integration_test/app_test.dart
Wenn alles funktioniert, sollte die Ausgabe in etwa so aussehen:
Multiple devices found:
Linux (desktop) • linux • linux-x64 • Ubuntu 22.04.1 LTS 5.15.0-58-generic
Chrome (web) • chrome • web-javascript • Google Chrome 109.0.5414.119
[1]: Linux (linux)
[2]: Chrome (chrome)
Please choose one (To quit, press "q/Q"): 1
00:00 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart B00:08 +0: loading /home/miquel/tmp/testing_app/integration_test/app_test.dart
00:26 +1: All tests passed!
8. App-Leistung mit Flutter Driver testen
Leistungstest schreiben
Erstellen Sie im Ordner integration_test eine neue Testdatei mit dem Namen perf_test.dart mit folgendem Inhalt:
integration_test/perf_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:testing_app/main.dart';
void main() {
group('Testing App Performance', () {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
testWidgets('Scrolling test', (tester) async {
await tester.pumpWidget(const TestingApp());
final listFinder = find.byType(ListView);
await binding.traceAction(() async {
await tester.fling(listFinder, const Offset(0, -500), 10000);
await tester.pumpAndSettle();
await tester.fling(listFinder, const Offset(0, 500), 10000);
await tester.pumpAndSettle();
}, reportKey: 'scrolling_summary');
});
});
}
Die Funktion ensureInitialized()
prüft, ob der Integrationstesttreiber initialisiert wurde, und initialisiert ihn gegebenenfalls neu. Das Festlegen von framePolicy
auf fullyLive
eignet sich gut zum Testen von animiertem Code.
Bei diesem Test wird sehr schnell durch die Liste der Artikel und dann ganz nach oben gescrollt. Mit der Funktion traceAction()
werden die Aktionen aufgezeichnet und eine Zusammenfassung des Zeitplans generiert.
Leistungsergebnisse erfassen
Erstellen Sie zum Erfassen der Ergebnisse einen Ordner namens test_driver
mit einer Datei namens perf_driver.dart
und fügen Sie den folgenden Code hinzu:
test_driver/perf_driver.dart.
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_summary'] as Map<String, dynamic>);
final summary = driver.TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(
'scrolling_summary',
pretty: true,
includeSummary: true,
);
}
},
);
}
Test durchführen
Schließen Sie Ihr Gerät an die Stromversorgung an oder starten Sie den Emulator.
Gehen Sie in der Befehlszeile zum Stammverzeichnis des Projekts und geben Sie den folgenden Befehl ein:
$ flutter drive \
--driver=test_driver/perf_driver.dart \
--target=integration_test/perf_test.dart \
--profile \
--no-dds
Wenn alles funktioniert, sollte die Ausgabe in etwa so aussehen:
Running "flutter pub get" in testing_app...
Resolving dependencies...
archive 3.3.2 (3.3.6 available)
collection 1.17.0 (1.17.1 available)
js 0.6.5 (0.6.7 available)
matcher 0.12.13 (0.12.14 available)
meta 1.8.0 (1.9.0 available)
path 1.8.2 (1.8.3 available)
test 1.22.0 (1.23.0 available)
test_api 0.4.16 (0.4.18 available)
test_core 0.4.20 (0.4.23 available)
vm_service 9.4.0 (11.0.1 available)
webdriver 3.0.1 (3.0.2 available)
Got dependencies!
Running Gradle task 'assembleProfile'... 1,379ms
✓ Built build/app/outputs/flutter-apk/app-profile.apk (14.9MB).
Installing build/app/outputs/flutter-apk/app-profile.apk... 222ms
I/flutter ( 6125): 00:04 +1: Testing App Performance (tearDownAll)
I/flutter ( 6125): 00:04 +2: All tests passed!
All tests passed.
Nach erfolgreichem Abschluss des Tests enthält das Build-Verzeichnis im Stammverzeichnis des Projekts zwei Dateien:
scrolling_summary.timeline_summary.json
enthält die Zusammenfassung. Öffnen Sie die Datei mit einem Texteditor, um sich die darin enthaltenen Informationen anzusehen.scrolling_summary.timeline.json
enthält die vollständigen Zeitachsendaten.
Weitere Informationen zu Integrationstests finden Sie hier:
9. Glückwunsch!
Sie haben das Codelab abgeschlossen und verschiedene Möglichkeiten zum Testen einer Flutter-App kennengelernt.
Das haben Sie gelernt
- Anbieter mithilfe von Einheitentests testen
- Widgets mit dem Widget-Test-Framework testen
- So testen Sie die UI der App mithilfe von Integrationstests
- So testen Sie die Leistung der App mithilfe von Integrationstests
Weitere Informationen zu Tests in Flutter finden Sie unter