| name | coverage-measurement |
| description | Measure code coverage honestly across mobile stacks — JaCoCo (JVM), llvm-cov (iOS), lcov (Flutter), Jest (RN) — and report it to Codecov / Coveralls without chasing meaningless numbers. Use when setting up coverage or when asked to raise a coverage gate. |
Coverage Measurement
Instructions
Coverage is a trend, not a target number. A 90 % line-coverage suite full of assertion-free smoke tests is worse than a 60 % suite with sharp, behavior-focused tests. Measure coverage, publish the trend, let engineers see gaps — but do not weaponize a single percentage as a gate.
1. What Coverage Actually Tells You
- Line / statement coverage — did each line execute? Cheap, widely supported, easy to fake.
- Branch coverage — did both sides of each conditional execute? More signal than line coverage.
- Modified-lines coverage (diff coverage) — of the lines this PR changed, what % is now covered? The single most useful metric for PR review.
Prefer branch + diff coverage over a single total-line percentage.
2. Android / Kotlin — JaCoCo
plugins { id 'jacoco' }
jacoco { toolVersion = '0.8.12' }
tasks.register('jacocoTestReport', JacocoReport) {
dependsOn 'testDebugUnitTest'
reports { xml.required = true; html.required = true }
sourceDirectories.setFrom(files(['src/main/java', 'src/main/kotlin']))
classDirectories.setFrom(files([
fileTree(dir: "$buildDir/tmp/kotlin-classes/debug", excludes: [
'**/R.class','**/R$*.class','**/BuildConfig.*','**/*_Factory*','**/Hilt_*'
])
]))
executionData.setFrom(fileTree(dir: buildDir, includes: ['**/*.exec','**/*.ec']))
}
For instrumented tests, add debug { testCoverageEnabled true } and merge .ec + .exec in the same report.
3. iOS — llvm-cov / xccov
Enable in the test scheme: Test → Options → Code Coverage.
Extract from .xcresult in CI:
xcrun xccov view --report --json DerivedData/Build/Logs/Test/<uuid>.xcresult > coverage.json
Convert to lcov for Codecov:
xcresultparser --output-format cobertura *.xcresult > coverage.xml
Exclude generated sources (Mock files, *.pbobjc.*, *.swift-generated.*) via .codecov.yml.
4. Flutter / Dart — lcov
flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
Filter out generated files:
lcov --remove coverage/lcov.info \
'*/generated/*' '*.g.dart' '*.freezed.dart' '*.mocks.dart' \
-o coverage/lcov.info
5. React Native — Jest
"scripts": { "test:coverage": "jest --coverage" },
"jest": {
"coverageReporters": ["lcov", "text-summary", "cobertura"],
"collectCoverageFrom": [
"src/**/*.{ts,tsx}",
"!src/**/*.d.ts",
"!src/**/__generated__/**"
]
}
6. Publishing
- Codecov — the
codecov/codecov-action@v4 uploader handles lcov, cobertura, and jacoco XML.
- Coveralls — similar; pick one, not both.
- Upload after every test job; distinguish unit, integration, and UI coverage with the
flags: feature so each layer's contribution is visible.
.codecov.yml sketch:
coverage:
status:
project:
default:
target: auto
threshold: 0.5%
patch:
default:
target: 80%
ignore:
- "**/generated/**"
- "**/*.g.dart"
- "**/*Tests*/**"
7. Exclusions — The Honest List
Exclude from coverage (via tool config, not via @SuppressLint):
- Generated code (Dagger/Hilt, KSP,
freezed, protobuf, Moshi adapters).
data class auto-generated methods.
- Trivial view bindings (
onClick { callback() }).
- Main entry points (
main(), AppDelegate boot, App.tsx root).
Do not exclude your own untested code to make the number look better. That is fraud against your future self.
8. Diff Coverage in PRs
Show diff coverage prominently on PRs. A PR that drops project coverage by 0.1 % but has 95 % coverage on the lines it changed is healthy. A PR with 100 % project coverage and 0 % diff coverage is adding dead weight.
9. Coverage Is Not Quality
Covered lines with no assertions are worthless. Run mutation testing occasionally to sanity-check assertion strength:
- Kotlin:
pitest via info.solidsoft.pitest plugin.
- Dart:
mutation_test or gutenberg.
- TS:
stryker-mutator.
Mutation scores of 70 %+ on core logic are a stronger signal than any line-coverage number.
10. Honest Goals
Good guidance to post in your repo:
- New files: aim for high diff coverage on business logic; UI glue can be lower.
- Overall trend: never regress for two consecutive releases without a written reason.
- Branch coverage on core modules (state machines, pricing, auth): > 80 %.
- Everything else: track, do not gate.
11. Checklist