Flutter widget vs Flutter driver

Issue

I’m writing tests for a mobile App written in Flutter.
I followed this Flutter Cookbook on testing Flutter apps, to learn how to write widget and integration tests.

This tutorial works perfectly, but I’m still stuck with my own Integration tests.

To simplify, let’s assume I have an app, containing only a TextField:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyAppp',
      home: Scaffold(
        body: Center(child: TextField()),
      ),
    );
  }
}

I want to write a test for this app. For instance, I want to test the following scenario:

  • Open the app
  • Check that the TextField is empty
  • Select the TextField
  • Enter "hello, world!"
  • Check that TextField contains "hello, world!"

I wrote the following Widget test, which works fine:

void main() {
  testWidgets('TextField behavior', (WidgetTester tester) async {
    // Create app
    await tester.pumpWidget(MyApp());

    // Find TextField, check there is 1
    final textFieldFinder = find.byType(TextField);
    expect(textFieldFinder, findsOneWidget);

    // Retrieve TextField Widget from Finder
    TextField textField = tester.widget(textFieldFinder);

    // Check TextField is empty
    expect(textField.controller.text, equals(""));

    // Enter text
    await tester.enterText(textFieldFinder, "hello, world!");

    // Check TextField contains text
    expect(textField.controller.text, equals("hello, world!"));
  });
}

This test passes, but I wanted to write an Integration test, doing more or less the same, to be able to test it on a real device.
Indeed if this Widget test passes, it will probably pass on all device. But in my app I have more complex widgets and interactions between them, I want to be able to launch tests on both Android and iOS.

I tried to write integration tests using Flutter driver, but I did not find what I wanted in the documentation and examples.

How can I check Widget properties, to verify that my App behaves as expected?

I wrote the following sample:

import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';

void main() {
  group('TextField', () {
    final textFieldFinder = find.byType('TextField');

    FlutterDriver driver;

    setUpAll(() async {
      driver = await FlutterDriver.connect();
    });

    tearDownAll(() async {
      if (driver != null) {
        driver.close();
      }
    });

    test('TextField behavior', () async {
      // ??? how to check that the TextField is empty

      await driver.tap(textFieldFinder);
      await driver.enterText("hello, world!");

      // ??? how to check that the TextField contains hello, world!
    });
  });
}

The Flutter Cookbook tutorial explains how to retrieve an object by its Text, this would help to check if the Text is present, but for instance is it possible to check that a Container color is red?
Where is the limit between Widget and Integration tests?

Writing Widget tests is pretty straighforward, but I didn’t find many examples or documentation about how to write more complexe integration tests using Flutter driver.

Solution

If anyone is interested:

To be able to test what I want (not only the presence of widgets, but also theirs states, their properties,…) test driver was not enough for me.

What I did in my project, is to use the flutter_test to write widget tests and check the properties I want.

To test it on a real device (Android or iOS), I used the integration_test package (previously e2e package) available here, which adapts flutter_test results to a format compatible with flutter drive.

To use integration_test, add this line in the main of your widget tests:

IntegrationTestWidgetsFlutterBinding.ensureInitialized();

Then create a file (e.g. integration_test.dart) in your test_driver folder with this content:

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();

Then you can launch these driver test by running:

flutter drive \
  --driver=test_driver/integration_test.dart \
  --target=test/widget_test/widget_test.dart

With your widgets tests wrote in the file test/widget_test/widget_test.dart.

It really helped me, since some widgets did not have the same behavior on Android and iOS.

Today I use both flutter_test (launched on real device with integration_test) and real flutter_driver tests:

  • I write widget tests to check a single widget, or a single page,
  • I use flutter driver to write more sophisticated scenarios to test the whole application.

Answered By – Lucie

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.