- 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 integration testing
Unit tests and Widget tests are handy for testing individual classes, functions, or Widgets. However, they generally don’t test how individual pieces work together as a whole or capture the performance of an application running on a real device. These tasks are performed with integration tests.
Integration tests work as a pair: first, deploy an instrumented application to a real device or emulator and then “drive” the application from a separate test suite, checking to make sure everything is correct along the way.
To create this test pair, we can use the flutter_driver package. It provides tools to create instrumented apps and drive those apps from a test suite.
In this recipe, we’ll learn how to test a counter app. It will demonstrate how to setup integration tests, how to verify specific text is displayed by the app, how to tap on specific Widgets, and how to run integration tests.
Directions
- Create an app to test
- Add the
flutter_driver
dependency - Create the test files
- Instrument the app
- Write the integration tests
- Run the integration test
1. Create an app to test
First, we’ll create an app that we can test! In this example, we’ll test the counter app produced by the flutter create
command. This app allows a user to tap on a button to increase a counter.
Furthermore, we’ll also need to provide a ValueKey
to the Text
and FloatingActionButton
Widgets. This allows us to identify and interact with these specific Widgets inside the test suite.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Counter App',
home: MyHomePage(title: 'Counter App Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
// Provide a Key to this specific Text Widget. This allows us
// to identify this specific Widget from inside our test suite and
// read the text.
key: Key('counter'),
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
// Provide a Key to this the button. This allows us to find this
// specific button and tap it inside the test suite.
key: Key('increment'),
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
2. Add the flutter_driver
dependency
Next, we’ll need the flutter_driver
package to write integration tests. We can add the flutter_driver
dependency to the dev_dependencies
section of our apps’s pubspec.yaml
file.
We also add the test
dependency in order to use actual test functions and assertions.
dev_dependencies:
flutter_driver:
sdk: flutter
test: any
3. Create the test files
Unlike unit and widget tests, integration test suites do not run in the same process as the app being tested. Therefore, we need to create two files that reside in the same directory. By convention, the directory is named test_driver
.
- The first file contains an “instrumented” version of the app. The instrumentation allows us to “drive” the app and record performance profiles from a test suite. This file can be given any name that makes sense. For this example, create a file called
test_driver/app.dart
. - The second file contains the test suite, which drives the app and verifies it works as expected. The test suite can also record performance profiles. The name of the test file must correspond to the name of the file that contains the instrumented app, with
_test
added at the end. Therefore, create a second file calledtest_driver/app_test.dart
.
This leaves us with the following directory structure:
counter_app/
lib/
main.dart
test_driver/
app.dart
app_test.dart
4. Instrument the app
Now, we can instrument the app. This will involve two steps:
- Enable the flutter driver extensions
- Run the app
We will add this code inside the test_driver/app.dart
file.
import 'package:flutter_driver/driver_extension.dart';
import 'package:counter_app/main.dart' as app;
void main() {
// This line enables the extension
enableFlutterDriverExtension();
// Call the `main()` function of your app or call `runApp` with any widget you
// are interested in testing.
app.main();
}
5. Write the tests
Now that we have an instrumented app, we can write tests for it! This will involve four steps:
- Create
SeralizableFinders
to locate specific Widgets - Connect to the app before our tests run in the
setUpAll
function - Test the important scenarios
- Disconnect from the app in the
teardownAll
function after our tests complete
// Imports the Flutter Driver API
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
void main() {
group('Counter App', () {
// First, define the Finders. We can use these to locate Widgets from the
// test suite. Note: the Strings provided to the `byValueKey` method must
// be the same as the Strings we used for the Keys in step 1.
final counterTextFinder = find.byValueKey('counter');
final buttonFinder = find.byValueKey('increment');
FlutterDriver driver;
// Connect to the Flutter driver before running any tests
setUpAll(() async {
driver = await FlutterDriver.connect();
});
// Close the connection to the driver after the tests have completed
tearDownAll(() async {
if (driver != null) {
driver.close();
}
});
test('starts at 0', () async {
// Use the `driver.getText` method to verify the counter starts at 0.
expect(await driver.getText(counterTextFinder), "0");
});
test('increments the counter', () async {
// First, tap on the button
await driver.tap(buttonFinder);
// Then, verify the counter text has been incremented by 1
expect(await driver.getText(counterTextFinder), "1");
});
});
}
6. Run the tests
Now that we have an instrumented app and a test suite, we can run the tests! First, be sure to launch an Android Emulator, iOS Simulator, or connect your computer to a real iOS / Android device.
Then, run the following command from the root of the project:
flutter drive --target=test_driver/app.dart
This command:
- builds the
--target
app and installs it on the emulator / device - launches the app
- runs the
app_test.dart
test suite located intest_driver/
folder
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论