close

Code Coverage Calculation

This product is not supported for your selected Datadog site. ().

Overview

A commit usually has more than one coverage report. A CI pipeline might run unit, integration, and end-to-end tests in separate jobs. It might also split a test suite across parallel workers, or run the same suite against several runtime versions. Each of those jobs uploads its own report.

Datadog merges all of the reports it receives for the same repository and commit into a single dataset. The total coverage and patch coverage of a commit are computed from that merged dataset, not from any individual report. You don’t need to merge reports yourself before uploading them.

Because merging happens on the Datadog side, the coverage percentage shown in Datadog can differ from the percentage reported by a single coverage tool run. For related guidance, see Discrepancy between Datadog UI and coverage report values.

Report merging

Merging is keyed on the repository and commit SHA pair. Every report uploaded for the same repository and commit contributes to the same merged dataset, regardless of which CI job, pipeline, or machine produced it.

Merging is incremental. As each report arrives, its data is added to the merged dataset and the coverage values are recomputed. A commit’s coverage reflects every report received for it so far. Wait until all of your CI jobs have finished uploading before comparing coverage percentages to PR Gate thresholds or to values from a single local report.

The merged dataset is also the basis for the following:

  • The total and patch coverage displayed for a commit and for its pull request
  • PR Gate evaluation
  • Per-service and per-code-owner coverage in Monorepo Support

Flags add a second layer on top of this. Reports sharing a flag are merged together into that flag’s own dataset, while the unflagged view merges every report for the commit. For details, see How flags work with report merging.

If carryforward is enabled, reports carried forward from ancestor commits are merged in the same way as reports uploaded directly for the commit.

Line coverage statuses

Within the merged dataset, each executable line of each file has one of the following statuses:

StatusMeaning
CoveredThe line was executed, and if it contains branches, every branch was executed.
Partially coveredThe line was executed, but not all of its branches were.
UncoveredThe line was never executed.

Non-executable lines, such as comments, blank lines, and closing brackets, are excluded from coverage calculations. For coverage tools that report these lines as uncovered, see Inaccurate coverage from non-executable lines.

Files present in multiple reports

When the same file appears in more than one report, Datadog merges the file’s line data instead of picking one report over another. An executable line is counted as covered when any of the reports containing that file marks it as covered.

For example, consider a commit with two reports that both contain src/checkout.go:

LineUnit test reportIntegration test reportMerged result
10CoveredUncoveredCovered
11UncoveredCoveredCovered
12UncoveredUncoveredUncovered

The merged coverage of a commit is therefore usually higher than the coverage of any single report. Splitting a test suite across parallel CI jobs does not lower the reported coverage.

Partial coverage

A line is partially covered when it was executed but not all of its branches were. This applies to if statements as well as ternary operators, and to any other construct where a single line contains multiple execution paths.

For example, in the following line, only one of the two paths runs if user is always non-null in your tests:

const name = user ? user.name : "anonymous";

The line is executed, so it is not uncovered, but the "anonymous" branch is never taken, so the line is reported as partially covered.

Partially covered lines are not counted as covered. They do not contribute to the total coverage percentage or to the patch coverage percentage. To count such a line as covered, add test cases that exercise all of its branches.

Partial coverage is derived from the branch data in your coverage reports. If your coverage tool or report format doesn’t include branch information, lines that were executed are reported as covered rather than partially covered.

Further reading