Use Flutter Hot Restart in the Integration Test

Reduce time on building integration tests

Mahdi Shahbazi
Flutter Community
4 min readSep 18, 2023

--

Flutter hot restart in integration test
Photo by Luke van Zyl on Unsplash

Introduction

If you strike up a conversation with a Flutter developer on Flutter’s unique attributes, chances are they will be quick to highlight Hot Restart and Hot Reload. Often coming from an Android or iOS development background, they have spent years enduring lengthy app build times. Flutter brings the advantage of implementing changes into a running app within a heartbeat using these features, significantly enhancing the development pace.

The Challenge

Typically, Flutter developers employ the use of the integration_test suite (now a built-in package) to create comprehensive integration tests for their apps. The recommended Flutter approach is to run these integration tests using the flutter drive. This process involves building the app, executing the tests, terminating it, and finally, uninstalling it from the device. Thus, every time a test is due to run, developers must wait for the app to build and install on the device — the very issue we sought to avoid by wasting time on building.

This results in the time spent writing integration tests potentially exceeding that of actual app development. How can we persuade management to allocate time for writing integration tests when the current perception is that it’s a time-consuming endeavor? Moreover, an integration test can easily fail due to an inadvertent error during the initial writing phase, requiring another lengthy wait. How is this efficiently manageable?

The Solution: Build at the Start of the Day and Utilise the Rest of it

Let’s use this example from Flutter. The directory structure of the app would look similar to this:

lib/
...
integration_test/
foo_test.dart
bar_test.dart
test/
# Other unit tests go here.
test_driver/
integration_test.dart

In this case, integration_test.dart is our test driver, and we have two integration test files: foo_test.dart and bar_test.dart.
Flutter’s suggested strategy for executing these tests involves a command that requires a fresh build every time:

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

We’ll employ the flutter run command to work around this issue, albeit with a different target. It builds the app, executes the tests, but importantly keeps the app active. Hence, you can deploy the hot restart to restart a test with the new modifications. So, the command would be:

flutter run integration_test/foo_test.dart

You can conveniently add this to your IDE configurations to build the app with this approach. It also allows debugging of integration tests using the IDE.

Configure hot restart for flutter integration test
Configure hot restart for flutter integration test

But what if you run with foo_test.dart and wish to run tests within bar_test.dart later? It’s pretty straightforward — just reroute foo_test.dart to call the main function of bar_test.dart.

import '../bar_test.dart' as bar_test;

void main() {
bar_test.main();
}

A New Hurdle

Even with this innovative solution, a build still needs to be executed at least once every day, which continues to eat into our development time. Plus, what happens if our device gets disconnected? Is there a solution to these challenges?

Solution: Build Once, Utilize Many Times

Don’t forget that any app built with flutter run can be reattached with flutter attach. You just need to execute it with the same target file, like so:

flutter attach integration_test/foo_test.dart

With the same configuration in Android Studio, you can use the flutter attach button to link an older app to Flutter and use hot restart to run new tests.

Attach to running flutter
Attach to running flutter

However, a minor constraint is that if your file has multiple test cases, it only cycles through all of them after the first restart when you run/attach the app. But fear not, this is not a significant issue. After all, reattaching doesn’t take much time and you can comment on the first test and use the hot restart to execute the next test. Each of your test cases should be independent; if they can run consecutively, it means they can also run one after the other.

Conclusion

The core concept of Flutter revolves around time efficiency. Starting as a multifunctional mobile platform, it has now branched out into a cross-client device platform. If you find a process time-consuming, there might be a more effective approach you’re missing. Embrace the Flutter way!

Thanks for reading.

--

--