Testing Flutter apps

The more features your app has, the harder it is to test manually. Automated tests help ensure that your app performs correctly before you publish it, while retaining your feature and bug fix velocity.

Automated testing falls into a few categories:

  • A unit test tests a single function, method, or class.
  • A widget test (in other UI frameworks referred to as component test) tests a single widget.
  • An integration test tests a complete app or a large part of an app.

Generally speaking, a well-tested app has many unit and widget tests, tracked by code coverage, plus enough integration tests to cover all the important use cases. This advice is based on the fact that there are trade-offs between different kinds of testing, seen below.

  Unit Widget Integration
Confidence Low Higher Highest
Maintenance cost Low Higher Highest
Dependencies Few More Most
Execution speed Quick Slower Slowest

Unit tests

A unit test tests a single function, method, or class. The goal of a unit test is to verify the correctness of a unit of logic under a variety of conditions. External dependencies of the unit under test are generally mocked out. Unit tests generally don’t read from or write to disk, render to screen, or receive user actions from outside the process running the test.

Recipes

Widget tests

A widget test (in other UI frameworks referred to as component test) tests a single widget. The goal of a widget test is to verify that the widget’s UI looks and interacts as expected. Testing a widget involves multiple classes and requires a test environment that provides the appropriate widget lifecycle context.

For example, the Widget being tested should be able to receive and respond to user actions and events, perform layout, and instantiate child widgets. A widget test is therefore more comprehensive than a unit test. However, like a unit test, a widget test’s environment is replaced with an implementation much simpler than a full-blown UI system.

Recipes

Integration tests

An integration test tests a complete app or a large part of an app. The goal of an integration test is to verify that all the widgets and services being tested work together other as expected. Furthermore, you can use integration tests to verify your app’s performance.

Generally, an integration test runs on a real device or an OS emulator, such as iOS Simulator or Android Emulator. The app under test is typically isolated from the test driver code to avoid skewing the results.

Recipes

Continuous integration services

Continuous integration (CI) services allow you to run your tests automatically when pushing new code changes. This provides timely feedback on whether the code changes work as expected and do not introduce bugs.

For information on running tests on various continuous integration services, please see the following: