Integration Testing in Flutter

Summary

In this lesson we'll cover:

The Code for This Lesson

You can check out the step/step09 branch here which will contain the code for this lesson.

Core Concepts

How Integration Tests Work in Flutter

"Driving" Our Application

Adding flutter_driver

# pubspec.yaml

# ...

dev_dependencies:
  # ...
  flutter_driver:
    sdk: flutter
  
  # ...

Adding test/test_driver/app.dart

// test/test_driver/app.dart

import 'package:flutter_driver/driver_extension.dart';
import 'package:tourismandco/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();
}

NOTE: Original source here.

Writing an Integration Test

Before We Continue

Understanding What Widget Keys Are

Adding Widget Keys for our Test

// lib/screens/locations/locations.dart

// ...

// NOTE _itemBuilder() is can existing method you'll have implemented in this file, 
// so you're just adding the 'key' property here...
Widget _itemBuilder(BuildContext context, Location location) {
    return GestureDetector(
      // ...
      key: Key('location_list_item_${location.id}'),

// ...
// lib/widgets/location_tile.dart

// ...

@override
Widget build(BuildContext context) {
// ...

return Container(
    // ...
        children: [
        Text(
            // ..
            key: Key('location_tile_name_${location.id}'),

// ...

Implemeting our Integration Test

// test/test_driver/app_test.dart

// Imports the Flutter Driver API
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';
import 'package:tourismandco/models/location.dart';

void main() {
  group('happy path integration tests', () {
    final locations = Location.fetchAll();

    // 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 locationListItemTextFinder =
        find.byValueKey('location_list_item_${locations.first.id}');
    
    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('a location name appears in location list', () async {
      // Use the `driver.getText` method to verify the counter starts at 0.
      expect(await driver.getText(locationTileOverlayTextFinder), isNotEmpty);
    });

    // NOTE one more test to come in the next step!
  });
}

Running Our Integration Test

Adding One Additional Test Case

// test/test_driver/app_test.dart

// ...

void main() {
  group('happy path integration tests', () {
    // ...

    final locationTileOverlayTextFinder =
        find.byValueKey('location_tile_name_${locations.first.id}');

    // ...

    test('a location in the list is tappable', () async {
      // First, tap on the button
      await driver.tap(locationTileOverlayTextFinder);

      // Use the `driver.getText` method to verify the counter starts at 0.
      expect(await driver.getText(locationTileOverlayTextFinder), isNotEmpty);
    });

    // ...

Summary

Sources