BugMojoBugMojoBugMojo
FeaturesPricingBlogHelpAbout
Add to ChromeLog inGet started
BugMojoBugMojo

Bug reports that actually help fix bugs — capture, replay, share.

A product of Softech Infra.

Product

  • Features
  • Pricing
  • Browser extension
  • Get started
  • Log in

Resources

  • Help & guides
  • Blog
  • Compare
  • Glossary

Company

  • About
  • Contact
  • Security
  • Privacy
  • Terms
  • Sitemap
© 2026 BugMojo. All rights reserved.
AllGuidesEngineeringPlaybooksCompareGlossaryAlternativesBy roleBug tracking by framework
  1. Home
  2. Blog
  3. Glossary
  4. What Is Code Coverage? (And Why 100% Isn't the Goal)
Glossary

What Is Code Coverage? (And Why 100% Isn't the Goal)

Code coverage is a metric that measures the percentage of your code executed by your automated tests. Here is what the number actually means, the types of coverage, and why chasing 100% is the wrong target.

ManviManvi·Jul 16, 2026·9 min read
Glossary
Isometric line-art of coverage signals — lines, branches, functions, statements — converging into a single code-coverage percentage node, lime on a dark canvas
TL;DR
  • Code coverage is a metric: the percentage of your code that runs when your automated tests run.
  • A tool instruments the code and records which lines, branches, and functions were executed during the suite.
  • Types, weakest to strongest: line/statement → function → branch/decision → condition/path. Branch beats line because a line can run without both outcomes being tested.
  • The catch: coverage measures what's executed, not verified. 100% with assertion-free tests proves nothing.
  • Use it to find untested critical paths, not to hit a magic number. A pragmatic 70–80% plus judgment beats a mandated 100%.

Definition

Code coverage is a metric that measures the percentage of your source code executed by your automated tests. A tool instruments the code and records which lines, branches, and functions ran during the test suite. It reports what your tests touch — not whether those tests actually verified that the code behaved correctly.

Mechanically, it works like this. A coverage tool instruments your code — it inserts invisible bookkeeping so that every time a line, a branch, or a function executes, a counter ticks. You run your test suite, the counters accumulate, and at the end the tool divides executed code by total code and hands you a percentage. When a report says 82% line coverage, it means 82% of your executable lines ran at least once while the tests were running. The other 18% never ran at all, which is a genuinely useful thing to know.

The ISTQB glossary puts it more formally: coverage is 'the degree to which specified coverage items are exercised by a test suite, expressed as a percentage.' The phrase to hold onto is exercised. Coverage tells you a piece of code was reached during testing. It does not — and cannot — tell you whether the test that reached it checked that the code did the right thing. That gap is the entire reason this article exists, and we will return to it.

The types of coverage

'Coverage' is not one number — it is a family of metrics that measure different things, from cheap-and-shallow to expensive-and-thorough. The four you will actually meet, weakest to strongest:

  • Line / statement coverage — which lines (or statements) executed at least once. The most quoted number and the easiest to inflate. It answers only 'did this line ever run?'
  • Function / method coverage — which functions were called at least once. Coarse, but a fast smoke check for whole modules that no test ever touches.
  • Branch / decision coverage — for every if, else, ternary, and loop condition, were both the true and false outcomes taken? Meaningfully stronger than line coverage.
  • Condition / path coverage — did every boolean sub-condition take both values (condition), or did every distinct route through the function execute (path)? The strongest, and the rarest.
Why branch coverage beats line coverage

Consider if (user.isAdmin) grantAccess(); on a single line. A test where isAdmin is true executes that line — 100% line coverage for it. But the false path, where access should not be granted, was never tested. Branch coverage catches this: it demands both outcomes. A line can run without both of its branches being exercised, which is exactly the kind of gap line coverage hides and branch coverage exposes.

Condition and path coverage go further still. A single decision like if (a && b) has multiple boolean sub-conditions, and a function with several branches has many possible routes through it. Exercising all of them is genuinely thorough — but the number of paths grows combinatorially with each added branch, which is why full path coverage is impractical for most codebases and is generally reserved for safety-critical software (avionics, medical devices) where a missed path can cost lives. For everyday product work, branch coverage is the sweet spot: much stronger than line coverage, without the combinatorial explosion.

How teams use it — and how it goes wrong

In practice, coverage shows up in two places. First, as a CI gate: a threshold that fails the build if coverage drops below, say, 75%, or if a pull request lowers the project's overall figure. Second, as a diagnostic: you open the coverage report, look at the red (un-executed) lines, and discover that your payment-retry logic or your error-handling branch has no tests at all. That second use is where coverage earns its keep — it is a map of what your suite ignores.

The trouble starts when the number becomes the goal. Here is the crucial, honest point that gives this article its title: coverage measures what is executed, not what is verified. Those are not the same thing. A test can call a function, run every one of its lines, and then assert nothing whatsoever about the result. The coverage tool sees the code run and dutifully counts it. The dashboard turns green. And you have learned precisely nothing about whether the code is correct.

Coverage measures what your tests execute, never what they verify. A suite can hit 100% coverage while asserting nothing — running every line, checking no behavior. A green coverage number is evidence your tests touched the code, not evidence the code is correct or the tests are any good.

Martin Fowler has a name for the failure mode: assertion-free testing — tests that exercise code without any assertions checking that it did the right thing. They exist precisely because a coverage target creates the incentive to write them. If your bonus, your CI, or your team's pride hinges on hitting 100%, the fastest route is not better tests; it is more tests that touch code without checking it. Coverage goes up, real defect-catching power stays flat, and everyone feels safer while being no safer at all.

Goodhart's law, applied to coverage

'When a measure becomes a target, it ceases to be a good measure.' Coverage is a textbook case. As a diagnostic it is honest — it shows you what your tests never run. As a target it corrupts: it rewards gaming (assertion-free tests, trivial getters tested to pad the number) over the hard work of asserting real behavior on the paths that matter. The moment '100% coverage' becomes the objective, the number stops telling you anything about quality.

Isometric diagram contrasting a green 100 percent coverage bar backed by empty assertion-free tests against a 78 percent bar backed by dense behavior-checking assertions, lime accents on a dark canvas
Two suites, same code. The 100% bar runs every line and asserts nothing; the 78% bar checks real behavior on the paths that matter. Coverage cannot tell these apart — only your assertions can.

What good use of coverage looks like

None of this means coverage is useless — it means you should use it as a flashlight, not a finish line. Fowler's own guidance in Test Coverage is blunt: coverage is a useful tool for finding untested parts of a codebase, but it is 'of little use as a numeric statement of how good your tests are.' The productive move is to invert the question. Instead of 'how do we get from 78% to 100%?', ask 'which of the paths my tests don't touch actually matter, and are any of them critical?'

Concretely, good practice looks like this: run branch coverage, not just line coverage, so the number means more. Read the report to hunt for untested critical paths — auth, payments, data integrity, error handling — and write assertion-rich tests for those specifically. Set a pragmatic floor (many teams land around 70–80%) that is low enough to be met with genuinely useful tests rather than gamed with filler. And treat the floor as a smoke alarm for regressions, not a badge. A well-judged 80% with strong assertions beats a gamed 100% every time.

It also pairs well with other signals. Test-driven development tends to produce high coverage as a byproduct — you write the test first, so the code that exists is code a test drove into being, and it comes with real assertions attached. That is coverage earned honestly, not chased. And knowing which layer to test — unit, integration, or end-to-end — matters far more than the aggregate percentage, because a unit-tested function with a broken integration is still a broken feature at 100% unit coverage.

Honest limits

Be clear-eyed about what coverage can and can't do. It tells you which code your tests touch — never whether those tests are any good. It cannot see a missing assertion, a test that checks the wrong thing, or a whole category of input you never imagined. High coverage on a thin test suite is a comfortable illusion. Coverage is one honest input among several (code review, mutation testing, real bug reports) — not a verdict on quality.

This connects to a broader trap worth naming: coverage is easy to turn into a vanity metric — a number that looks reassuring on a dashboard while telling leadership little about whether the product actually works. The metrics that matter measure escaped defects, mean time to resolution, and user-facing reliability. Coverage informs those; it does not replace them. A team optimizing for the coverage bar instead of for shipped correctness is optimizing for the wrong thing.

FeatureAspectCoverage as a diagnosticCoverage as a 100% target
What it optimizes for—Finding untested critical pathsHitting a number
Incentive it creates—Write meaningful, assertion-rich testsWrite assertion-free tests that game the metric
Preferred metric type—Branch / decision coverageLine coverage (easiest to inflate)
Typical healthy signal—~70–80% with strong assertions100% with unknown assertion quality
Tells you the tests are good———
Coverage as a diagnostic (good) versus coverage as a target (Goodhart's law kicks in).

And here is the limit that no coverage number can escape, which is where a bug tracker enters the story. Coverage can only report on code your tests run. It is structurally blind to the bugs your tests never imagined — the input shape you didn't anticipate, the race condition on a slow network, the interaction between two features nobody tested together. Those defects sail past a 100% coverage gate untouched, because there was never a test to cover them in the first place. They reach real users, and then they need reproduction, not a coverage report.

Key takeaway

Code coverage is the percentage of your code that your tests execute — a diagnostic, not a grade. Prefer branch over line coverage, use it to hunt untested critical paths, and set a pragmatic floor (70–80%) instead of chasing 100%. Never forget the boundary: coverage tells you what your tests touch, never whether they're any good — and it is silent about the bugs your tests never imagined, which are the ones that reach users.

Coverage can't see the bug your tests never imagined

A 100% coverage gate is blind to the defects that reach real users — the ones no test covered. BugMojo captures those in the wild: an rrweb session replay, the console, and the network state behind the failure, handed to Claude Code or Cursor over MCP so your agent can reproduce and fix what your suite missed.

Install the extension

Frequently asked questions

Frequently asked questions

Sources

  1. Test Coverage — why coverage is a useful diagnostic but a poor target (Martin Fowler) — martinfowler.com (2026)
  2. Code coverage — line, branch, function and condition coverage defined — Wikipedia (2026)
  3. Assertion-Free Testing — tests that execute code without checking behavior — martinfowler.com (2026)
  4. Coverage — 'The degree to which specified coverage items are exercised by a test suite' (ISTQB Glossary) — ISTQB (2026)
Share:
Manvi
Manvi· QA Tester

Manvi is a Quality Assurance Tester with three years of experience. For her, quality is not just about finding bugs — it is about ensuring the best possible experience for every user.

On this page

  • Definition
  • The types of coverage
  • How teams use it — and how it goes wrong
  • What good use of coverage looks like

Get bug-tracking insights, weekly.

Engineering deep-dives, QA playbooks, and honest tool comparisons. No spam — unsubscribe in one click.