- Install
- Set up an editor
- Test drive
- Write your first Flutter app, part 1
- Learn more
- Flutter for Android developers
- Flutter for iOS developers
- Flutter for React Native developers
- Flutter for web developers
- Flutter for Xamarin.Forms developers
- Introduction to declarative UI
- Cookbook
- Codelabs
- Tutorials
- User interface
- Introduction to widgets
- Layouts in Flutter
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Introduction to animations
- Animations overview
- Animations tutorial
- Hero Animations
- Staggered Animations
- Advanced UI
- Slivers
- Taps, drags, and other gestures
- Widget catalog
- Data & backend
- State management
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Firebase
- Accessibility & internationalization
- Accessibility
- Internationalizing Flutter apps
- Platform integration
- Writing custom platform-specific code
- Packages & plugins
- Using packages
- Developing packages & plugins
- Background processes
- Tools & techniques
- Android Studio / IntelliJ
- Visual Studio Code
- Upgrading Flutter
- Hot reload
- Code formatting
- Debugging Flutter apps
- Using OEM debuggers
- Flutter's build modes
- Testing Flutter apps
- Performance best practices
- Flutter performance profiling
- Creating flavors for Flutter
- Preparing an Android App for Release
- Preparing an iOS App for Release
- Continuous Delivery using fastlane with Flutter
- Bootstrap into Dart
- Inside Flutter
- Platform specific behaviors and adaptations
- Technical Overview
- Technical videos
- FAQ
- Flutter widget index
- Install
- Windows install
- MacOS install
- Linux install
- Set up an editor
- Write your first Flutter app, part 1
- Learn more
- Cupertino (iOS-style) widgets
- Layout widgets
- Animation and motion widgets
- Retrieve the value of a text field
- Basic widgets
- Material Components widgets
- Animate the properties of a Container
- Fade a Widget in and out
- Add a Drawer to a screen
- Displaying SnackBars
- Exporting fonts from a package
- Updating the UI based on orientation
- Using Themes to share colors and font styles
- Using custom fonts
- Working with Tabs
- Building a form with validation
- Create and style a text field
- Focus on a Text Field
- Handling changes to a text field
- Retrieve the value of a text field
- Adding Material Touch Ripples
- Handling Taps
- Implement Swipe to Dismiss
- Display images from the internet
- Fade in images with a placeholder
- Working with cached images
- Basic List
- Create a horizontal list
- Creating a Grid List
- Creating lists with different types of items
- Place a floating app bar above a list
- Working with long lists
- Report errors to a service
- Animating a Widget across screens
- Navigate to a new screen and back
- Navigate with named routes
- Pass arguments to a named route
- Return data from a screen
- Send data to a new screen
- Fetch data from the internet
- Making authenticated requests
- Parsing JSON in the background
- Working with WebSockets
- Persist data with SQLite
- Reading and Writing Files
- Storing key-value data on disk
- Play and pause a video
- Take a picture using the Camera
- An introduction to integration testing
- Performance profiling
- Scrolling
- An introduction to unit testing
- Mock dependencies using Mockito
- An introduction to widget testing
- Finding widgets
- Tapping, dragging and entering text
- Development
- Introduction to widgets
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Navigate to a new screen and back
- Send data to a new screen
- Return data from a screen
- Navigate with named routes
- Animating a Widget across screens
- AnimatedList
- Sample App Catalog
- Animations overview
- Animations tutorial
- Staggered Animations
- Slivers
- Taps, drags, and other gestures
- Accessibility widgets
- Assets, images, and icon widgets
- Async widgets
- Input widgets
- Interaction model widgets
- Painting and effect widgets
- Scrolling widgets
- Styling widgets
- Text widgets
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Accessibility
- Internationalizing Flutter apps
- Writing custom platform-specific code
- Using packages
- Fetch data from the internet
- Developing packages & plugins
- Background processes
- Android Studio / IntelliJ
- Set up an editor
- Flutter inspector
- Creating Useful Bug Reports
- Visual Studio Code
- Set up an editor
- Upgrading Flutter
- Hot reload
- Code formatting
An introduction to widget testing
In the introduction to unit testing recipe, we learned how to test Dart classes using the test
package. In order to test Widget classes, we’ll 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
, which allows us to build and interact with Widgets in a test environment. - The
testWidgets
function. This function will automatically create a newWidgetTester
for each test case, and is used in place of the normaltest
function. Finder
classes. These allow us to search for Widgets in the test environment.- Widget-specific
Matcher
constants, which help us verify whether aFinder
locates a Widget or multiple Widgets in the test environment.
If this sounds overwhelming, don’t worry! We’ll see how all of these pieces fit together throughout this recipe.
Directions
- Add the
flutter_test
dependency - Create a Widget to test
- Create a
testWidgets
test - Build the Widget using the
WidgetTester
- Search for our Widget using a
Finder
- Verify our Widget is working using a
Matcher
1. Add the flutter_test
dependency
Before we can begin writing tests, we’ll need to include the flutter_test
dependency in the dev_dependencies
section of our pubspec.yaml
file. If you create a new Flutter project with the command line tools or code editor, this dependency should already be in place!
dev_dependencies:
flutter_test:
sdk: flutter
2. Create a Widget to test
Next, we’ll need to create a Widget that we can test! For this recipe, we’ll create a Widget that displays a title
and message
.
class MyWidget extends StatelessWidget {
final String title;
final String message;
const MyWidget({
Key key,
@required this.title,
@required this.message,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text(message),
),
),
);
}
}
3. Create a testWidgets
test
Now that we have a Widget to test, we can begin writing our first test! To get started, we’ll use the testWidgets
function provided by the flutter_test
package to define a test. The testWidgets
function will allow us to define a Widget test and will create a WidgetTester
for us to work with.
Our test will verify that MyWidget
displays a given title and message.
void main() {
// Define a test. The TestWidgets function will also provide a WidgetTester
// for us to work with. The WidgetTester will allow us to build and interact
// with Widgets in the test environment.
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
// Test code will go here!
});
}
4. Build the Widget using the WidgetTester
Next, we’ll want to build MyWidget
inside the test environment. To do so, we can use the pumpWidget
method provided by the WidgetTester
. The pumpWidget
method will build and render the Widget we provide.
In this case, we’ll 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 tell the tester to build it
await tester.pumpWidget(MyWidget(title: 'T', message: 'M'));
});
}
Note
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, if we tap a button, and this button calls setState
, Flutter will not automatically rebuild your Widget in the test environment. We need to use one of the following methods to ask Flutter to build our Widget once again.
- tester.pump()
- Triggers a rebuild of the Widget after a given duration.
- 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.
5. Search for our Widget using a Finder
Now that we’ve built our Widget in the test environment, we’ll want to search through the Widget tree for the title
and message
Text Widgets using a Finder
. This will allow us to verify that we’re displaying these Widgets correctly!
In this case, we’ll use the top-level find
method provided by the flutter_test
package to create our Finders
. Since we know we’re looking for Text
widgets, we can use the find.text
method.
For more information about Finder
classes, please see the Finding Widgets in a Widget Test recipe.
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
await tester.pumpWidget(MyWidget(title: 'T', message: 'M'));
// Create our Finders
final titleFinder = find.text('T');
final messageFinder = find.text('M');
});
}
6. Verify our Widget is working using a Matcher
Finally, we can 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 our expectations.
In this case, we want to ensure our Widgets appear on screen exactly one time. Therefore, we can use the findsOneWidget
Matcher
.
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
await tester.pumpWidget(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 our
// 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 one or more Widgets are found
- findsNWidgets
- verifies a specific number of Widgets are found
Complete example
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
// Define a test. The TestWidgets function will also provide a WidgetTester
// for us to work with. The WidgetTester will allow us to build and interact
// with Widgets in the test environment.
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
// Create the Widget tell the tester to build it
await tester.pumpWidget(MyWidget(title: 'T', message: 'M'));
// Create our Finders
final titleFinder = find.text('T');
final messageFinder = find.text('M');
// Use the `findsOneWidget` matcher provided by flutter_test to verify our
// Text Widgets appear exactly once in the Widget tree
expect(titleFinder, findsOneWidget);
expect(messageFinder, findsOneWidget);
});
}
class MyWidget extends StatelessWidget {
final String title;
final String message;
const MyWidget({
Key key,
@required this.title,
@required this.message,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text(message),
),
),
);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论