Contents
- Setup
- Automated Collection
- Flutter-Specific Coverage
- Manual VM Service Workflow
- Coverage Ignore Directives
- CI Integration
- Workflow: Generating Coverage Reports
- Examples
Setup
Add coverage strictly as a dev_dependency:
Dart project:
dart pub add dev:coverage
Flutter project:
flutter pub add dev:coverage
Automated Collection
Use the bundled test_with_coverage script for one-command coverage:
dart run coverage:test_with_coverage
This automatically:
- Runs all tests
- Collects JSON coverage from the Dart VM
- Formats into LCOV report at
coverage/lcov.info
Monorepo support — specify test directories explicitly:
dart run coverage:test_with_coverage -- pkgs/foo/test pkgs/bar/test
Flutter-Specific Coverage
Generate LCOV
flutter test --coverage
Outputs coverage/lcov.info at project root.
Generate HTML Report
# Install lcov (macOS)
brew install lcov
# Generate HTML from LCOV
genhtml coverage/lcov.info -o coverage/html
# Open in browser
open coverage/html/index.html
Filter Out Generated Code
lcov --remove coverage/lcov.info \
'*.g.dart' \
'*.freezed.dart' \
'*.part.dart' \
-o coverage/lcov_cleaned.info
Manual VM Service Workflow
For granular control over coverage collection (branch/function-level):
1. Run Tests with VM Service
dart run --pause-isolates-on-exit \
--disable-service-auth-codes \
--enable-vm-service=8181 \
test &
2. Collect Raw Coverage
dart run coverage:collect_coverage \
--wait-paused \
--uri=http://127.0.0.1:8181/ \
-o coverage/coverage.json \
--resume-isolates \
--function-coverage \
--branch-coverage
Optional flags:
--function-coverage— function-level metrics (Dart VM 2.17.0+)--branch-coverage— branch-level metrics (Dart VM 2.17.0+)
3. Format to LCOV
dart run coverage:format_coverage \
--packages=.dart_tool/package_config.json \
--lcov \
-i coverage/coverage.json \
-o coverage/lcov.info \
--check-ignore
Coverage Ignore Directives
Exclude specific code from coverage metrics using inline comments. Pass --check-ignore during formatting to enforce.
| Directive | Scope | Usage |
|---|---|---|
// coverage:ignore-line |
Single line | Unreachable branches, platform checks |
// coverage:ignore-start / // coverage:ignore-end |
Block | Generated code, legacy methods |
// coverage:ignore-file |
Entire file | Generated files, config files |
// coverage:ignore-file
// This entire file is excluded from coverage
class GeneratedRoutes {
// coverage:ignore-start
void legacyInit() {
print('Deprecated initialization');
}
// coverage:ignore-end
bool isProduction(String env) {
if (env == 'prod') return true;
return false; // coverage:ignore-line
}
}
CI Integration
GitHub Actions Coverage Gate
- name: Run tests with coverage
run: flutter test --coverage
- name: Check coverage threshold
run: |
COVERAGE=$(lcov --summary coverage/lcov.info 2>&1 | grep "lines" | awk '{print $2}' | sed 's/%//')
echo "Coverage: $COVERAGE%"
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage below 80% threshold!"
exit 1
fi
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
files: coverage/lcov.info
Coverage Targets (from AGENTS.md)
- 100% logic coverage for
domainandbloclayers. - Widget coverage for all major UI components.
- Use
// coverage:ignore-filefor generated code (.g.dart,.freezed.dart).
Workflow: Generating Coverage Reports
Task Progress
- [ ] Step 1: Add
coveragetodev_dependencies. - [ ] Step 2: Run
flutter test --coverage(ordart run coverage:test_with_coverage). - [ ] Step 3: Validate
coverage/lcov.infoexists. - [ ] Step 4: Filter generated code:
lcov --remove ... '*.g.dart' '*.freezed.dart'. - [ ] Step 5: Generate HTML:
genhtml coverage/lcov.info -o coverage/html. - [ ] Step 6: Review uncovered files — add tests or
// coverage:ignore-file. - [ ] Step 7: Add coverage gate to CI pipeline (80% minimum).
Examples
pubspec.yaml Configuration
name: my_app
environment:
sdk: ^3.0.0
dev_dependencies:
flutter_test:
sdk: flutter
coverage: ^1.15.0
bloc_test: ^9.1.0
mocktail: ^1.0.0
Quick Coverage Check Script
#!/bin/bash
# scripts/coverage.sh
set -e
echo "Running tests with coverage..."
flutter test --coverage
echo "Filtering generated code..."
lcov --remove coverage/lcov.info \
'*.g.dart' '*.freezed.dart' '*.part.dart' \
-o coverage/lcov_cleaned.info
echo "Generating HTML report..."
genhtml coverage/lcov_cleaned.info -o coverage/html
echo "Opening report..."
open coverage/html/index.html