How to generate test coverage for a multi-package flutter project?

I am currently working on a multi-package flutter project and using melos to manage it. I want to generate test coverage for all my local packages.

I would love to know how others have solved this problem in a multi-package ecosystem.

I can give you the scripts i have running for our multi module package repositories that generate code coverage report and html output for all packages using Melos in a single unified coverage report. You may have to tweak some things but it should be able to get something working.

dart-test.sh

#!/usr/bin/env bash

# Fast fail the script on failures.
set -e

# Run Dart tests with coverage reporting
echo "Running tests with coverage..."
dart test --reporter json --coverage="coverage" > tests.json

# Generate LCOV coverage report
echo "Generating coverage report..."
format_coverage \
  --lcov \
  --in=coverage \
  --out=coverage/lcov.info \
  --packages=.dart_tool/package_config.json \
  --report-on=lib

# Remove absolute paths from coverage report
echo "Processing coverage report..."
escapedPath="$(echo `pwd` | sed 's/\//\\\//g')"
sed "s/$escapedPath//" coverage/lcov.info > coverage/lcov.info.tmp
mv coverage/lcov.info.tmp coverage/lcov.info

flutter-test.sh

#!/usr/bin/env bash

set -e 
set -o pipefail 

flutter test --exclude-tags golden --no-pub --coverage --branch-coverage --machine | tee tests.json

coverage-report.sh

#!/usr/bin/env bash

# Fast fail the script on failures.
# Exit on any error
set -e

# Filter out generated files from coverage report
melos exec -c 1 --file-exists=coverage/lcov.info -- \
  coverde filter \
  --input ./coverage/lcov.info \
  --output $MELOS_ROOT_PATH/coverage/lcov.info \
  --filters \.g\.dart,\.graphql\.dart,\.freezed\.dart \
  --filters '.*\/generated\/*' \
  --paths-parent $MELOS_PACKAGE_PATH

# Generate HTML coverage report
genhtml $MELOS_ROOT_PATH/coverage/lcov.info \
  --output=coverage \
  --no-function-coverage \
  --branch-coverage \
  --ignore-errors inconsistent \
  --ignore-errors category

# Save coverage metrics to file
coverde value -i $MELOS_ROOT_PATH/coverage/lcov.info > $MELOS_ROOT_PATH/coverage/result.txt

# Install Python dependencies for coverage conversion
if ! command -v pip3 &> /dev/null; then
  apt-get -yq -qq install python3-pip
fi

# Install lcov_cobertura converter
pip3 install lcov_cobertura --quiet --break-system-packages

# Convert lcov to Cobertura format
lcov_cobertura $MELOS_ROOT_PATH/coverage/lcov.info

melos.yml

  test:flutter:ci:
    description: Execute Flutter tests with coverage for CI
    run: MELOS_ROOT_PATH/scripts/flutter-test.sh
    packageFilters:
      flutter: true
      ignore:
        - "*demo*"
    exec:
      failFast: false

  test:dart:ci:
    description: Run Dart tests with coverage CI
    exec: MELOS_ROOT_PATH/scripts/dart-test.sh
    packageFilters:
      flutter: false

  test:report:
    description: Convert the test report.
    run: tojunit -i tests.json -o test-report.xml
    exec:
      failFast: true
    packageFilters:
      fileExists: "./tests.json"

  test:coverage:
    description: Merge all packages coverage tracefiles ignoring data related to generated files.
    run: MELOS_ROOT_PATH/scripts/coverage-report.sh
    packageFilters:
      fileExists: "./test-report.xml"

  test:ci:
    description: Run all the tests with coverage report!
    run: |
      melos run test:flutter:ci && \
      melos run test:dart:ci && \
      melos run test:report && \
      melos run test:coverage

You need to install

  • Pub.dev coverde
  • python
  • genhtml
  • lcov_cobertura
  • melos
2 Likes

Thank you so much for the script. I ended up something very similar to this. Curious to know if you had a MIN_COVERAGE check for individual packages?