An introduction to widget testing
In the introduction to unit testing recipe,
you learned how to test Dart classes using the test
package.
To test widget classes, you need a few additional tools provided by the
flutter_test
package, which ships with the Flutter SDK.
The flutter_test
package provides the following tools for
testing widgets:
- The
WidgetTester
allows building and interacting with widgets in a test environment. - The
testWidgets()
function automatically creates a newWidgetTester
for each test case, and is used in place of the normaltest()
function. - The
Finder
classes allow searching for widgets in the test environment. - Widget-specific
Matcher
constants help verify whether aFinder
locates a widget or multiple widgets in the test environment.
If this sounds overwhelming, don’t worry. Learn how all of these pieces fit together throughout this recipe, which uses the following steps:
- Add the
flutter_test
dependency. - Create a widget to test.
- Create a
testWidgets
test. - Build the widget using the
WidgetTester
. - Search for the widget using a
Finder
. - Verify the widget using a
Matcher
.
flutter_test
dependency
1. Add the Before writing tests, include the flutter_test
dependency in the dev_dependencies
section of the pubspec.yaml
file.
If creating a new Flutter project with the command line tools or
a code editor, this dependency should already be in place.
dev_dependencies:
flutter_test:
sdk: flutter
2. Create a widget to test
Next, create a widget for testing. For this recipe,
create a widget that displays a title
and message
.
class MyWidget extends StatelessWidget { const MyWidget({ Key? key, required this.title, required this.message, }) : super(key: key); final String title; final String message; @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: Scaffold( appBar: AppBar( title: Text(title), ), body: Center( child: Text(message), ), ), ); } }
testWidgets
test
3. Create a With a widget to test, begin by writing your first test.
Use the testWidgets()
function provided by the
flutter_test
package to define a test.
The testWidgets
function allows you to define a
widget test and creates a WidgetTester
to work with.
This test verifies that MyWidget
displays a given title and message.
It is titled accordingly, and it will be populated in the next section.
void main() { // Define a test. The TestWidgets function also provides a WidgetTester // to work with. The WidgetTester allows you to build and interact // with widgets in the test environment. testWidgets('MyWidget has a title and message', (WidgetTester tester) async { // Test code goes here. }); }
WidgetTester
4. Build the widget using the Next, build MyWidget
inside the test environment by using the
pumpWidget()
method provided by WidgetTester
.
The pumpWidget
method builds and renders the provided widget.
Create a MyWidget
instance that displays “T” as the title
and “M” as the message.
void main() { testWidgets('MyWidget has a title and message', (WidgetTester tester) async { // Create the widget by telling the tester to build it. await tester.pumpWidget(const MyWidget(title: 'T', message: 'M')); }); }
Notes about the pump() methods
After the initial call to pumpWidget()
, the WidgetTester
provides
additional ways to rebuild the same widget. This is useful if you’re
working with a StatefulWidget
or animations.
For example, tapping a button calls setState()
, but Flutter won’t
automatically rebuild your widget in the test environment.
Use one of the following methods to ask Flutter to rebuild the widget.
tester.pump(Duration duration)
- Schedules a frame and triggers a rebuild of the widget.
If a
Duration
is specified, it advances the clock by that amount and schedules a frame. It does not schedule multiple frames even if the duration is longer than a single frame.
tester.pumpAndSettle()
- Repeatedly calls
pump()
with the given duration until there are no longer any frames scheduled. This, essentially, waits for all animations to complete.
These methods provide fine-grained control over the build lifecycle, which is particularly useful while testing.
Finder
5. Search for our widget using a With a widget in the test environment, search
through the widget tree for the title
and message
Text widgets using a Finder
. This allows verification that
the widgets are being displayed correctly.
For this purpose, use the top-level find()
method provided by the flutter_test
package to create the Finders
.
Since you know you’re looking for Text
widgets, use the
find.text()
method.
For more information about Finder
classes, see the
Finding widgets in a widget test recipe.
void main() { testWidgets('MyWidget has a title and message', (WidgetTester tester) async { await tester.pumpWidget(const MyWidget(title: 'T', message: 'M')); // Create the Finders. final titleFinder = find.text('T'); final messageFinder = find.text('M'); }); }
Matcher
6. Verify the widget using a Finally, verify the title and message Text
widgets appear on screen
using the Matcher
constants provided by flutter_test
.
Matcher
classes are a core part of the test
package,
and provide a common way to verify a given
value meets expectations.
Ensure that the widgets appear on screen exactly one time.
For this purpose, use the findsOneWidget
Matcher
.
void main() { testWidgets('MyWidget has a title and message', (WidgetTester tester) async { await tester.pumpWidget(const MyWidget(title: 'T', message: 'M')); final titleFinder = find.text('T'); final messageFinder = find.text('M'); // Use the `findsOneWidget` matcher provided by flutter_test to verify // that the Text widgets appear exactly once in the widget tree. expect(titleFinder, findsOneWidget); expect(messageFinder, findsOneWidget); }); }
Additional Matchers
In addition to findsOneWidget
, flutter_test
provides additional
matchers for common cases.
findsNothing
- Verifies that no widgets are found.
findsWidgets
- Verifies that one or more widgets are found.
findsNWidgets
- Verifies that a specific number of widgets are found.
matchesGoldenFile
- Verifies that a widget’s rendering matches a particular bitmap image (“golden file” testing).
Complete example
import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { // Define a test. The TestWidgets function also provides a WidgetTester // to work with. The WidgetTester allows building and interacting // with widgets in the test environment. testWidgets('MyWidget has a title and message', (WidgetTester tester) async { // Create the widget by telling the tester to build it. await tester.pumpWidget(const MyWidget(title: 'T', message: 'M')); // Create the Finders. final titleFinder = find.text('T'); final messageFinder = find.text('M'); // Use the `findsOneWidget` matcher provided by flutter_test to // verify that the Text widgets appear exactly once in the widget tree. expect(titleFinder, findsOneWidget); expect(messageFinder, findsOneWidget); }); } class MyWidget extends StatelessWidget { const MyWidget({ Key? key, required this.title, required this.message, }) : super(key: key); final String title; final String message; @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: Scaffold( appBar: AppBar( title: Text(title), ), body: Center( child: Text(message), ), ), ); } }