Test Coverage

Updated Sep 15, 2026

Test coverage records which parts of a codebase execute while automated tests run, commonly at the level of lines, branches, functions, or statements. In a legacy codebase audit, it helps locate behaviour with automated protection and areas where refactoring needs additional tests or other forms of verification.

Test coverage reports which code executes when an automated test suite runs. It can record lines, branches, statements, or functions depending on the language and tool. In a legacy codebase, coverage provides evidence about where automated checks exist, but it does not prove that those checks verify the right behaviour.

What coverage measures

A coverage tool observes execution. If a test calls a function, its lines may count as covered. If the test follows one side of a condition, the other branch can remain uncovered. Different measurements therefore answer different questions about the same suite.

Coverage typeWhat it recordsWhat it does not prove
Line coverageLines executed by testsCorrect outputs or assertions
Branch coverageDecision outcomes exercisedComplete business scenarios
Function coverageFunctions calledMeaningful behaviour checked
Statement coverageStatements executedSafe interaction between components

Coverage data must be read with the tests. A suite can execute code without checking its result. It can also protect critical behaviour with a small number of focused tests while leaving routine code uncovered.

Why legacy coverage is uneven

Older systems often contain code from different periods, teams, and testing practices. Core modules may have extensive unit tests while scheduled jobs, integration points, or user interface flows rely on manual checks. Some tests may no longer run in the current build or may depend on environments that are difficult to reproduce.

A legacy codebase audit checks whether the suite can run, what it covers, and what its assertions protect. It also identifies business-critical paths that lack reliable verification even when the overall report appears healthy.

How coverage informs refactoring

Coverage helps a team decide where to add a safety net before changing behaviour. The aim is to capture what the system currently does at the boundary being moved or rewritten.

A practical sequence is:

  1. Run the existing suite. Establish which tests are reliable in the current environment.
  2. Map critical behaviour. Connect business flows to the code that implements them.
  3. Find uncovered paths. Focus on paths affected by the planned change.
  4. Add verification. Use unit, integration, or end-to-end tests at the appropriate boundary.
  5. Change in small steps. Run the checks as each part moves.

What coverage cannot replace

Coverage does not reveal whether requirements are correct, whether production data contains unexpected cases, or whether two components share an undocumented assumption. Those questions need domain knowledge, runtime evidence, and architectural analysis.

Missing or unreliable tests can form part of technical debt, especially where teams avoid changing important code because they cannot verify the result. Coverage analysis helps scope that debt and supports the takeover of an unfamiliar codebase by showing where automated evidence exists and where review must supply it.