JaCoCo Code Coverage Setup Guide
Overview
This project uses JaCoCo (Java Code Coverage) to measure test coverage for unit tests and instrumented tests.
Setup Completed
1. Plugin Configuration
Added JaCoCo plugin to app/build.gradle.kts:
plugins {
jacoco
}
jacoco {
toolVersion = "0.8.12"
}2. Build Type Configuration
Enabled coverage in debug build type:
buildTypes {
debug {
enableUnitTestCoverage = true
enableAndroidTestCoverage = true
}
}3. Memory Configuration
Increased heap size in gradle.properties:
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
org.gradle.parallel=falseIncreased test heap in app/build.gradle.kts:
tasks.withType<Test> {
maxHeapSize = "2g"
jvmArgs("-XX:+UseG1GC")
}Available Tasks
Run Unit Tests with Coverage Report
./gradlew jacocoUnitTestReportThis will:
- Run all unit tests with coverage instrumentation
- Generate HTML report at:
app/build/reports/jacoco-unit/html/index.html - Generate XML report at:
app/build/reports/jacoco-unit/jacoco-unit.xml
Run Tests Only (Without Report)
./gradlew testDebugUnitTestRun Specific Test Class
./gradlew testDebugUnitTest --tests "io.github.mobilutils.ntp_dig_ping_more.DigViewModelTest"Viewing Reports
After running ./gradlew jacocoUnitTestReport, open the HTML report:
# macOS
open app/build/reports/jacoco-unit/html/index.html
# Linux
xdg-open app/build/reports/jacoco-unit/html/index.htmlThe report shows:
- Line Coverage: Which lines of code were executed
- Branch Coverage: Which conditional branches were taken
- Method Coverage: Which methods were called
- Class Coverage: Which classes were loaded and tested
Coverage Exclusions
The following are automatically excluded from coverage reports:
- Android generated code (R.class, BuildConfig, Manifest)
- Dagger/Hilt generated code
- Lambda classes
- Compose generated code (ComposableSingletons)
CI/CD Integration
GitHub Actions Example
- name: Run Tests with Coverage
run: ./gradlew jacocoUnitTestReport
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: app/build/reports/jacoco-unit/html/
- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: app/build/reports/jacoco-unit/jacoco-unit.xml
flags: unittestsCoverage Thresholds (Optional)
You can enforce minimum coverage thresholds by adding to app/build.gradle.kts:
tasks.jacocoUnitTestReport {
violationRules {
rule {
limit {
minimum = "0.60".toBigDecimal() // 60% minimum coverage
}
}
rule {
element = "CLASS"
limit {
minimum = "0.50".toBigDecimal() // 50% per class
}
excludes = listOf(
"**/*Activity*",
"**/*Composable*"
)
}
}
}Troubleshooting
OutOfMemoryError
If tests fail with OutOfMemoryError:
- Increase heap in
gradle.properties:org.gradle.jvmargs=-Xmx4096m - Increase test heap in
app/build.gradle.kts:maxHeapSize = "2g" - Stop Gradle daemon:
./gradlew --stop - Run with
--no-daemon:./gradlew jacocoUnitTestReport --no-daemon
No Coverage Data
If report shows 0% coverage:
- Ensure
enableUnitTestCoverage = truein build type - Clean and rebuild:
./gradlew clean testDebugUnitTest jacocoUnitTestReport - Check execution data exists:
ls app/build/jacoco/
Coverage Missing for Specific Classes
Check the exclusion filters in the JaCoCoReport task. Classes matching exclusion patterns won't be included.
Best Practices
- Run coverage on clean builds:
./gradlew clean jacocoUnitTestReport - Check HTML reports: More readable than XML
- Focus on new code: Ensure new code has adequate test coverage
- Set realistic thresholds: Start with 60-70%, increase over time
- Exclude generated code: Don't count auto-generated code in coverage
- Combine with quality gates: Use coverage as one metric, not the only one
Current Coverage Status
As of 2026-04-18:
- Total Tests: 174+ unit tests
- Test Files: 10 test files
- ViewModels Tested: 8 out of 9 (all except PingViewModel)
Coverage by Module (Estimated)
- ViewModels: High coverage (state management, input validation, error handling)
- Repositories: Partial (some use Android APIs that are hard to mock)
- History Stores: Full coverage (parsing logic tested)
- UI Components: Not yet covered (requires instrumented tests)
Next Steps
- Fix failing tests to get accurate coverage measurements
- Add PingViewModel tests
- Add instrumented tests for Compose UI
- Set up automated coverage gates in CI
- Integrate with Codecov or similar service for coverage tracking
- Create dashboard to track coverage trends over time