Code Coverage (Kover)¶
worker-kmp uses kotlinx-kover for line-coverage measurement + enforcement. Since v3.1.3, 8 testable commonMain modules carry a hard 100% line-coverage floor; CI fails PRs that regress below it.
Quick start¶
# Generate aggregate HTML report
./gradlew koverHtmlReport
open build/reports/kover/html/index.html # macOS
# Generate XML report (CI / codecov consumption)
./gradlew koverXmlReport
# Verify 100% line coverage per opted-in module (fails on regression)
./gradlew koverVerify
What's measured¶
Kover instruments JVM bytecode only. KMP commonMain code compiles to JVM (via jvmTest)
so it IS measured. iOS, JS, and wasmJs platform actuals do NOT get coverage — see the exclusions
below.
Modules in scope¶
| Module | Status |
|---|---|
cmp-worker-kmp |
100% commonMain |
cmp-worker-scheduler |
100% commonMain |
cmp-worker-store5 |
100% commonMain |
cmp-worker-storeflow |
100% commonMain |
cmp-worker-koin |
100% commonMain |
cmp-worker-compose |
100% commonMain |
cmp-worker-test |
100% commonMain |
cmp-worker-app-annotations |
excluded (annotation-only — no executable code) |
Modules NOT in scope (with rationale)¶
| Module | Why excluded |
|---|---|
cmp-worker-android, cmp-worker-ios, cmp-worker-desktop, cmp-worker-desktop-daemon, cmp-worker-web, cmp-worker-web-push |
Platform actuals; Kover only measures JVM bytecode. Tracked separately by the Tier-2 follow-up epic worker-kmp-platform-engine-tests, which adds Robolectric (Android) + Xcode-sim (iOS) + browser-test (Web) harnesses. |
cmp-worker-app-ksp, cmp-worker-app-plugin |
Build-tooling (KSP processor + Gradle plugin) — needs Gradle TestKit; deferred. |
cmp-worker-bench, cmp-worker-migrate |
Non-production tooling. |
samples/* |
Illustrative; not under coverage threshold. |
Exclusion patterns¶
The root KoverConventionPlugin
delegates to configureKoverRootReports() in
Kover.kt,
which excludes:
excludes {
classes(
"*.di.*", // Koin DI declarations
"*.BuildConfig", // Android-generated BuildConfig
"*ComposableSingletons*", // Compose generated lambda holders
"*_*Factory*", // Generated factories
"*\$ComposableLambda\$*",
"*Preview*", // @Preview functions
"*Test*", // Test helpers themselves
)
packages(
"*.generated.*",
"*.ksp.*",
"*.android", "*.ios", "*.jvm", "*.js", "*.wasmJs", // platform actuals
)
annotatedBy("androidx.compose.runtime.Composable")
}
The verify rule enforces:
This is LINE aggregation per the Kover 0.9.1 default; per-module — each opted-in module
gates its own bytecode.
Adding a new module¶
- Add
id("io.github.mobilebytelabs.kover")to the new module'sbuild.gradle.ktsplugins {}block. - The convention plugin auto-registers it with the root aggregator via
rootProject.dependencies.add("kover", project). ./gradlew :{new-module}:koverVerifywill start failing until 100% line coverage is reached.- If the new module is platform-heavy (mostly
androidMain/iosMain/ etc.), do NOT apply the plugin — add a row to the "Modules NOT in scope" table above and surface the gap in the Tier-2 follow-up epic.
Escape hatches¶
For provably-uncoverable lines (e.g. sealed when synthetic else branches that the bytecode
verifier mis-counts as missed), two options:
- Per-class exclusion — extend the
classes(...)list inKover.ktwith the FQN. Document the reason in a code comment. @ExcludeFromCoverage(future) — once the marker annotation lands, annotate the uncoverable member and reference it via the filter'sannotatedBy(...).
Every escape hatch must carry a code-comment rationale and a linked issue. The quarterly maintenance pass prunes stale exclusions.
CI workflow¶
The Test Coverage / Kover 100% gate job at
.github/workflows/test-coverage.yml runs on every
PR + push to main / development. It:
- Runs
./gradlew koverHtmlReport koverXmlReport koverVerify. - Uploads the aggregate HTML report as
kover-html-report(14-day retention). - Posts the aggregate
%to the PR Step Summary.
koverVerify exit ≠ 0 fails the PR. There is no soft-warn mode.
Related¶
- Coverage epic plan:
plan-layer/project-plans/mbs/worker-kmp/active/kover-100-coverage/ - Tier-2 platform-engine tests:
worker-kmp-platform-engine-tests - Convention plugin pattern:
convention-plugin.md