Integration Testing in Flutter: Getting Started
Learn how to test UI widgets along with the backend services in your Flutter project using Integration Testing. By Monikinderjit Singh.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Integration Testing in Flutter: Getting Started
30 mins
- Getting Started
- Setting Up a Firebase Project
- Setting Up The Android Project
- Setting Up The iOS Project
- Setting Up Authentication and Firestore
- Exploring the Starter Project
- Testing in Flutter
- Comparing Types of Testing
- Examining Unit Testing
- Examining Widget Testing
- Examining Integration Testing
- Setting Up the Project for Testing
- Adding Dependencies
- Creating a Test Directory
- Writing Your First Test
- Diving into LiveTestWidgetsFlutterBinding
- Grouping Tests
- Testing Feature One: Authentication
- Understanding pumpWidget and pumpAndSettle
- Diving Into Widget Keys
- Adding Fake Delays
- Understanding expect()
- Running the Test
- Testing Feature Two: Modifying Ideas
- Inserting New Ideas in a List
- Deleting an Idea
- Where to Go From Here?
Setting Up the Project for Testing
To create integration tests for Flutter, you’ll use the integration_test package. In the past, you would have used flutter_driver, but Flutter discontinued it for the following reasons:
- Difficulty in catching exceptions.
- Hard interaction with the app components like
showBottomSheet. - Poor readability of the API.
- Difficulty in verifying the state of the app.
The integration_test package solves these issues.
Now it’s time to learn how to configure your project to write integration tests. First, you’ll add all the required dependencies.
Adding Dependencies
The Flutter SDK includes integration_test package, so you don’t need to copy it from the Pub.dev website. Instead, you just need to add integration_test to your pubspec.yaml.
Open pubspec.yaml and replace # TODO: add integration test dependency here with:
integration_test:
sdk: flutter
Don’t forget to run flutter pub get in the terminal.
Now, you’ll create the test directory.
Creating a Test Directory
In the project’s root, create a folder named integration_test. This folder will act as a directory for all of the project’s integration tests.

Inside the integration_test folder, create a dart file named app_test.dart. This file will include your integration tests.
Now, it’s time to start writing integration tests.
Writing Your First Test
In app_test.dart, insert:
void main() {
}
This function is the first called when running the tests. You’ll write all tests inside this function.
At the top of app_test.dart, insert:
import 'package:integration_test/integration_test.dart';
Here, you import the integration_test package making it ready to use in the file.
Now, inside main(), add:
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Here, ensureInitialized() verifies the integration test driver’s initialization. It also reinitializes the driver if it isn’t initialized.
Next, you’ll learn how to use the LiveTestWidgetsFlutterBinding method.
Diving into LiveTestWidgetsFlutterBinding
Insert the following code at the top of app_test.dart:
import 'package:flutter_test/flutter_test.dart';
This code includes the flutter_test package required for configuring the test.
Then, add this code block below the binding variable you defined before:
if (binding is LiveTestWidgetsFlutterBinding) {
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
}
LiveTestWidgetsFlutterBindingFramePolicy defines how LiveTestWidgetsFlutterBinding should paint frames. fullyLive is a policy used to show every frame requested by the framework and is best suited for heavy animations.
Checkout the official docs for other policies that might make more sense for your app.
Next, you’ll work on grouping tests.
Grouping Tests
At the last line inside main(), insert:
group('end-to-end test', () {
//TODO: add random email var here
//TODO: add test 1 here
//TODO: add test 2 here
});
The group() method groups and runs many tests. You include it here since you’ll run multiple tests in the app. It has the following arguments:
- description: A description of the test group.
- void Function() body: A function defining what tests to run.
-
skip: An optional argument used to skip the test group. Since it’s dynamic, if the value is
Stringrather thantrue, it’ll print the value ofStringwhen skipping the test.
Now you have all the skills you need to create your first test!
Testing Feature One: Authentication
Most apps start with an authentication screen, and this project is no different. Therefore, you’ll start by writing an authentication test first.
Write the following code in place of //TODO: add random email var here:
final timeBasedEmail = DateTime.now().microsecondsSinceEpoch.toString() + '@test.com';
This code creates a time-based email address.
Now, replace //TODO: add test 1 here with:
testWidgets('Authentication Testing', (WidgetTester tester) async {
//TODO: add Firebase Initialization Here
});
testWidgets() lets you define tests for widgets and takes two required parameters:
- description: Defines what the test is about.
-
callback function: A function that executes during the test. It takes a
WidgetTesterobject as a parameter. ThisWidgetTesterobject interacts with the widgets and the test environment.
The callback function is asynchronous because your test will interact with real-world APIs.
testWidgets() also has some optional parameters like skip and timeout.
timeout is the maximum time required to run the test. After that time, the test will fail automatically. It’s ten minutes by default.
Insert the following lines at the top of app_test.dart:
import 'package:firebase_core/firebase_core.dart';
This code lets you initialize your Firebase app during the test.
Replace //TODO: add Firebase Initialization Here with:
await Firebase.initializeApp();
This code ensures your app is ready to use Firebase services.
Now, you’ll work with pumpWidget and pumpAndSettle.
Understanding pumpWidget and pumpAndSettle
At the top of app_test.dart, add:
//1
import 'package:ideast/main.dart';
//2
import 'package:flutter/material.dart';
Here’s a code breakdown:
- Imports main.dart to get access to
MyApp(). - Imports material.dart to access Flutter widgets.
Now, below the code you just added, add:
await Firebase.initializeApp(); // previous code
await tester.pumpWidget(MyApp());
await tester.pumpAndSettle();
//TODO: Add here
Here’s an explanation of the code:
duration is the most suitable option when you know how many frames will render, such as navigation without animations.
-
pumpWidget()renders the UI of the provided widget. Here you passMyApp()as the rendering widget.PumpWidgetalso takesdurationas a parameter, which will shift the fake clock by the specified duration to help you avoid excessive frame rates.durationis the most suitable option when you know how many frames will render, such as navigation without animations. -
pumpAndSettle()repeatedly callspumpfor a given duration until there are no frames to settle, which is usually required when you have some animations.pumpAndSettleis called afterpumpWidget()because you want to wait for the navigation animations to complete.
Replace //TODO: Add code here with:
await tester.tap(find.byType(TextButton));
//TODO: Add code here
tap() is a method in WidgetTester that lets you tap the centre of the widget. This requires a Finder to tell the framework to tap it.
The byType property defines the type of widget. TextButton and ElevatedButton are acceptable but not abstract classes such as StatefulWidget.
Replace //TODO: Add code here with:
//1
tester.printToConsole('SignUp screen opens');
//2
await tester.pumpAndSettle();
//3
await tester.enterText(find.byKey(const ValueKey('emailSignUpField')), timeBasedEmail);
Here’s a code breakdown:
-
printToConosleprints statements during the test. Including a few descriptive statements provides a sense comfort that the tests are running. - Waits for all animations to settle down.
- In the text field, you can enter text using the tester’s
enterTextproperty. There are two parameters: aFinderand aString.Stringenters this text into the Text field.byKeyfinds widgets using their widget keys.
In the next section, you’ll learn how to interact with the widgets using keys.