Code coverage: what the percentage actually measures

Code coverage measures the share of code executed by the tests: lines, statements, branches and functions, and why chasing 100% backfires.
3 min read
Believemy logo

A report announces ninety-two percent. The team breathes out. The following week a bug ships in a function the report counted as covered.

The number had not lied. It simply was not saying what everyone believed they had read.


Definition

Code coverage measures the share of the source code actually executed while the tests run. The tool instruments the program, records what was traversed, and hands back a line-by-line report. It measures a visit, never a verification.

JAVASCRIPT
export function discount(total, code) {
  if (code === "WELCOME") {
    return total * 0.9;
  }
  if (total > 100) {
    return total - 10;
  }
  return total;
}

A single test calling discount(50) travels through both conditions and the final return. The function counts as executed, three statements out of five are reached, yet neither of the two reductions was ever computed.


Four measurements, not one

MeasurementWhat it counts
LinesThe lines of the file that were reached
StatementsThe statements executed, sometimes several per line
BranchesEach outcome of an if, a switch or an Ternary operator (?:)
FunctionsThe functions called at least once

On the example above, function coverage reaches one hundred percent while branch coverage tops out at half. The branch column is the one carrying useful information, and it is the one people look at last.


Why chasing one hundred percent backfires

A threshold set too high changes the nature of the tests being written. People end up calling functions without asserting anything about the result, just to turn a red line green in the report. The suite grows, runtime climbs, and confidence does not move.

Good to know

High coverage does not prove the code is correct. It proves the code ran. A test with no expect covers exactly as many lines as a test verifying everything.


Frequently asked questions

Question

What threshold is reasonable?

Between seventy and eighty percent on branches suits most application projects, and a higher bar is justified on calculation or billing code. The most productive use is not the global threshold but the no-regression rule: forbidding the number from dropping between two versions.


Question

How is a report read without being fooled?

By opening the HTML report rather than reading the total. Uncovered lines appear highlighted there, and you almost always discover they are the error cases, the fallback branches and the guards that never get taken. Those are precisely the ones that break in production.


Question

What separates the two measurement engines?

The V8 one reads counters Node.js already maintains, so it is fast and leaves the code untouched. The Istanbul one rewrites the code to place its own counters, so it is slower but stays more precise on branches and on the mapping back to the original file. The first suits daily work, the second suits reports meant to be published.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.