Collecting code coverage during the Flutter Driver test
(this code uses an approach from the previous story when Flutter Driver connects to an already running application)
The final source code is available here: https://github.com/arturk/basic_app
So, let's get to the topic of code coverage with the Flutter Driver approach. It is very useful if you want to figure out whether your tests cover all the possible logical flows of the functionality.
In fact, it is very easy to build a code coverage solution with Flutter Driver.
We will utilize the Virtual Machine Service connection again. Basically, all we need to do is to get the data out of the Virtual Machine because it already is capable of collecting all that.
I will start by creating a simple flutter application with:
flutter create basic_app
It is necessary to add flutter_driver and test package dependencies to the pubspec.yaml file.
I will add the enableFlutterDriverExtension() call to the main function.
So now our app is ready for being used with flutter driver.
Now time for tests. First of all, I will use code from the previous story to write a function that can connect to an already running flutter application.
These are almost the same functions as were used in the previous article mentioned above. So you can read about those there.
Also, the latest Dart uses a slightly different for identifying the Observatory port in ADB logs. Instead of line.contains(‘Observatory’) you would do line.contains(‘Dart VM’).
One difference here is using the Invoker.current!.addTearDown(_writeCoverageData) code.
_writeCoverageData function is a function that will collect and parse the source coverage information from the Dart VM service. We will define it later.
Invoker.current!.addTearDown function call dynamically adds a tearDown function to the currently running test. So here it means, that if in a test setup we will use var driver = await initAdnroidFlutterDriver(); the teardown will be created automatically by the addTearDown function call and in teardown the logic of the _writeCoverageData function will be executed. Such an approach removes the necessity to write teardowns over and over again for each test and test suite across numerous files.
Next, we will create a function that will collect the source coverage data from virtual machine:
This is also is going to be a teardown function
So, we are using getSourceReport function of the Dart VM service to retrieve the source coverage. It will return every bit of code that exists in the application but we are interested only in code that was compiled. So we filter out rest of the garbage. Next we make the json more convenient by adding path to the source file in place to every block of source code coverage report. And finally we are filtering out only the code that was written by us, meaning that we want to check only the code that is part of the basic_app package.
So now we need to run the test and check the source coverage during the test. The test would be as simple as:
We have a setup where we use our custom driver initializer that will connect to the running flutter application. The initializer function will also create a hidden test teardown that will close the flutter driver when tests are over, write JSON coverage report.
Source_coverage.json will look like:
Here starPos and endPos point to code block start and end positions (bytes within file). While hits and misses in the coverage report show executed or skipped lines of code within the file starting from index 1. scriptUri is a path to the file that we added when parsing coverage json from Dart VM.
But we can go further and make a human-readable HTML page of the json by parsing the data.
So, after running the test we will have two files — JSON report of the source coverage and an HTML file showing which lines were executed and which were skipped:
Video example of running the application, testing, and getting source coverage report from this code is available here: