Code Coverage in Mobile Development: What It Is, Metrics, and How to Measure

Author: IT Sectr Published: 2026-04-09 Reading time: 9 min

Code Coverage is a metric that shows what percentage of an application’s source code is executed during testing. It helps assess test quality, identify untested areas, and prioritize writing new tests. According to Atlassian, 2025, the optimal coverage level is 70–80% — above this threshold, testing costs begin to outweigh the benefits.

Key Takeaways

  • Code Coverage — a metric measuring the percentage of code executed by tests
  • Coverage metrics include line, branch, function, condition, and path
  • Tools: JaCoCo for Android, XCCov for iOS, SonarQube for code analysis
  • Target coverage 70–80% — a balance between quality and test cost
  • CI/CD integration allows blocking builds when coverage drops below the threshold

What Is Code Coverage

Code Coverage is a quantitative metric that determines which part of the application’s source code was executed during tests. It is expressed as a percentage and calculated as the ratio of executed lines/branches to the total. High coverage does not guarantee zero bugs, but it reduces the risk of missed errors.

Why Measure Coverage

Code coverage helps the team: find untested code areas, make decisions about test writing priorities, and track testing quality trends in CI/CD. In mobile development, coverage is especially important for business logic, data models, and repositories — layers where error probability is highest.

Code Coverage Myths

A common myth: “100% coverage = perfect quality.” In practice, 100% coverage is extremely rare and often comes at the cost of superficial tests. Effective coverage is not a race for a percentage but a strategic coverage of critical paths and edge cases. Coverage says nothing about the quality of the tests themselves: a test may pass but fail to verify the correctness of the result.

Coverage Metrics

Several Code Coverage metrics exist, each measuring different aspects of testing. Line coverage is the simplest metric, showing the percentage of executed code lines. Branch coverage measures which if-else and switch branches were tested.

Line Coverage

Line coverage counts each source code line as executed or not. If a line contains a conditional operator or loop, the line is considered executed if control reached it, even if not all branches were processed. This is the least strict metric but the most understandable for visual assessment.

Branch Coverage

Branch coverage evaluates whether all possible branches in the code were tested. For each if-else, both branches (true and false) are considered. For switch, each case is considered. Branch coverage is considered a stricter metric than line coverage and more often reveals untested scenarios.

MetricWhat It MeasuresDifficulty to Achieve
LinePercentage of executed code linesLow
BranchPercentage of executed branches (if/else, switch)Medium
FunctionPercentage of called functions and methodsLow
ConditionPercentage of logical sub-expressions (&&, ||)High

Path Coverage

Path coverage is the strictest metric, requiring verification of all possible combinations of branches in a function. In practice, path coverage is rarely used due to the exponential growth in the number of combinations: a function with 10 branches has 1024 possible paths.

Tools for Measuring Coverage

In mobile development, various tools are used to measure Code Coverage depending on the platform. For Android, the standard is JaCoCo (Java Code Coverage), which integrates with Gradle and supports both unit tests and instrumentation tests. For iOS, XCCov is used, built into Xcode.

JaCoCo for Android

JaCoCo generates reports in HTML, XML, and CSV formats. The HTML report visually highlights lines: green — executed, red — missed, yellow — partially executed. The XML report is compatible with SonarQube and other code analysis systems. JaCoCo supports class filtering: generated code, databinding, and BuildConfig can be excluded.

groovy
// build.gradle — JaCoCo configuration
android {
    buildTypes {
        debug {
            testCoverageEnabled = true
        }
    }
}

// Generating JaCoCo report
task jacocoTestReport(type: JacocoReport) {
    dependsOn 'testDebugUnitTest'
    reports {
        xml.enabled = true
        html.enabled = true
    }
}

XCCov for iOS

XCCov is a built-in Xcode tool for measuring code coverage. It is enabled via Gather coverage data in the test scheme. XCCov supports coverage for Swift and Objective-C, generates reports in .xccovreport format, and integrates with CI via xcodebuild -enableCodeCoverage YES. Data is output to the console and can be exported in JSON.

SonarQube and Codecov

For centralized coverage monitoring, platforms like SonarQube (code quality analysis + coverage), Codecov, and Coveralls are used. These services aggregate data from JaCoCo and XCCov, show trends, Quality Gates, and integrate with GitHub/GitLab via PR comments.

How to Improve Code Coverage

Improving Code Coverage requires a systematic approach: not “pumping percentages” but closing risks. The first step is to analyze the JaCoCo or XCCov report — identifying red (uncovered) classes. Priority: business logic → repositories → ViewModel → UI components.

TDD Strategy

Test-Driven Development (TDD) automatically ensures high coverage because tests are written before implementation. The process: red (write a failing test) → green (write minimal code) → refactor. TDD disciplines the developer, forcing them to cover edge cases and exceptional situations that often remain untested.

Parameterized Tests

One parameterized test replaces dozens of ordinary ones. JUnit and XCTest support parameterization: @ParameterizedTest in JUnit 5, XCTestCase with testPerformanceExample in XCTest. Parameterization allows checking many input values without code duplication, significantly expanding branch and condition coverage.

kotlin
// Parameterized test in Kotlin with JUnit 5
@ParameterizedTest
@ValueSource(strings = ["user@test.com", "admin@test.com", "test@example.com"])
fun `validate email returns true for valid addresses`(email: String) {
    val result = EmailValidator.isValid(email)
    Assertions.assertTrue(result)
}

Common Code Coverage Mistakes

The most common mistake is chasing the percentage without analyzing test quality. The team starts writing tests for the sake of tests: checking getters and setters, duplicating coverage at different levels, testing trivial methods. This yields a high percentage but does not improve real quality.

False Sense of Security

High Code Coverage can create a false feeling that the application is well tested. A test may execute a line of code but not verify the correctness of the result. For example: a test calls a discount calculation method but does not check the amount — the line is executed, coverage grows, but the bug is not found.

Ignoring Edge Cases

A typical mistake is testing only the “happy path” and ignoring edge cases: empty lists, null values, maximum numbers, incorrect formats. Most bugs occur at boundaries and exceptions. Branch coverage helps identify missed branches but does not guarantee checking boundary values.

Mutation Testing — Evaluating Test Quality

Mutation Testing is a method for assessing test quality where mutations (artificial errors) are introduced into the source code, and it is checked whether the tests fail. Pitest is a popular mutation testing tool for Java and Kotlin. If tests do not fail on a mutation, they do not verify that particular condition.

How Pitest Works

Pitest creates mutants — modified copies of source code where, for example, > is replaced with >=, true with false, or a method call is removed. Then tests are run for each mutant. If tests pass — the mutant survived, meaning the tests do not cover that scenario. If tests fail — the mutant is killed, the test is valid.

groovy
// build.gradle — Pitest configuration
plugins {
    id 'info.solidsoft.pitest' version '1.15.0'
}

pitest {
    targetClasses = ['com.example.app.*']
    targetTests = ['com.example.app.*Test']
    threads = 4
    outputFormats = ['HTML', 'XML']
    mutationThreshold = 80
    coverageThreshold = 85
}

Mutation Types

Pitest supports many mutation types: changing conditional operators (== → !=, < → <=), removing method calls, replacing return values (true → false), changing arithmetic operations (+ → -), mutating increments (i++ → i--). The more mutation types are killed by tests, the more reliable the test suite.

Mutation Score Goal

The target mutation score is 80% and above. This means 80% of artificial errors are detected by tests. Code Coverage of 90% does not guarantee that tests find bugs — mutation testing provides a more objective assessment. Pitest can be integrated into CI as a Quality Gate, blocking the build if the mutation score drops below the threshold.

Integrating Code Coverage into CI/CD

For automated Code Coverage control in CI/CD, Quality Gates are used — threshold values that, when violated, mark the build as unstable or reject it. SonarQube allows configuring a Quality Gate based on a combination of metrics: coverage (≥80%), number of bugs, vulnerabilities, and duplicated code.

Setting Up Quality Gate in GitHub Actions

In GitHub Actions, Code Coverage is integrated through action steps: run tests with coverage → upload report to Codecov → check threshold. Codecov automatically comments on PRs with a coverage diff, showing which lines changed and how it affected the overall percentage. If coverage dropped, the PR is blocked until additional tests are written.

yaml
# GitHub Actions — uploading coverage to Codecov
- name: Run Tests with Coverage
  run: ./gradlew testDebugUnitTest jacocoTestReport

- name: Upload to Codecov
  uses: codecov/codecov-action@v4
  with:
    files: ./app/build/reports/jacoco/jacocoTestReport.xml
    flags: unittests
    fail_ci_if_error: true

- name: Check Coverage Threshold
  run: |
    coverage=$(grep -oP 'branchCoverage="\K[0-9.]+' report.xml)
    if (( $(echo "$coverage < 80" | bc -l) )); then
      echo "Coverage $coverage% is below 80% threshold"
      exit 1
    fi

Reporting and Visualization

HTML reports from JaCoCo and XCCov contain visual coverage highlighting: green — executed lines, red — not executed. SonarQube additionally shows coverage at the file, class, method, and line level, as well as coverage history across sprints. This helps make decisions about refactoring and adding tests.

Frequently Asked Questions

What percentage of Code Coverage is considered good?

For mobile projects, coverage of 70–80% for business logic and 50–60% for UI components is considered good. Above 80%, testing costs start to outweigh the benefits. It is important to remember that the percentage is not a goal but an indicator, and different modules may have different target levels.

What is the difference between Line and Branch Coverage?

Line Coverage shows how many lines of code were executed. Branch Coverage shows how many branches (if-else, switch) were tested. A line with if may be executed, but only the true branch may be tested, not the false one. Branch Coverage is stricter and reveals more missed scenarios.

How to integrate Code Coverage into CI/CD?

In CI/CD, coverage is integrated through a Quality Gate: the build is blocked if coverage falls below the threshold. For Android, JaCoCo + SonarQube is used; for iOS, xcodebuild -enableCodeCoverage with .xccovreport parsing. GitHub Actions has ready-made actions for Codecov.

Can coverage be measured for Jetpack Compose?

Yes, JaCoCo supports Jetpack Compose through the standard JVM coverage mechanism. However, Compose code contains many generated lambda expressions that JaCoCo may not fully cover. It is recommended to exclude generated compose code from the report using filters.

How to avoid false coverage?

False coverage occurs when a test executes code but does not verify the result. Solution: write assert checks for every important scenario, use mutation testing (Pitest) to verify test quality, and analyze not only the percentage but also which branches are covered.

Summary

  • Code Coverage — a metric showing the percentage of code executed by tests, but not guaranteeing the absence of bugs
  • Line and Branch coverage — main metrics; Branch is stricter and reveals untested branches
  • JaCoCo — standard tool for Android, XCCov — for iOS, both integrate with Gradle and Xcode
  • Target coverage 70–80% for business logic — an optimal balance between quality and cost
  • TDD and parameterization — effective methods for increasing coverage without test duplication
  • SonarQube and Codecov — platforms for centralized monitoring and Quality Gates in CI/CD
  • Main rule: don’t chase the percentage, but cover critical risks and edge cases

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also