Code coverage measures how much of your code actually executed while the test suite ran — most commonly reported as line coverage (what fraction of executable lines ran at least once) or branch coverage (what fraction of possible if/else, switch, and other decision paths were actually taken, in both directions).
def classify(n):
if n > 0:
return "positive"
else:
return "non-positive"
def test_classify_positive():
assert classify(5) == "positive"
That single test gives 100% line coverage of classify — every line ran — but only 50% branch coverage, since the else path never executed. Line coverage is the more commonly quoted number, and it's also the more easily gamed one, because it says nothing about whether every meaningful path through the code, or every edge case within a line, was actually exercised.
Coverage measures execution, not correctness — a line can run, every time, while still producing the wrong answer, as long as nothing ever checks the actual output:
def divide(a, b):
return a / b # no guard against b == 0
def test_divide():
assert divide(10, 2) == 5 # covers the one line, 100% line coverage... but proves almost nothing
This gives divide 100% line coverage. It also completely misses that divide(10, 0) raises ZeroDivisionError with zero handling — a real, live bug that a coverage report will never flag, because the report only ever asks "did this line execute," never "was the executed behavior correct for every input that matters." A test suite can sit at 100% coverage and still ship a division-by-zero crash to production, because coverage and correctness are simply answering two different questions.
Coverage is a negative signal, not a positive one: low coverage reliably tells you there's code nobody has checked at all, which is useful information. High coverage does not reliably tell you the code is correct — it only tells you the code ran during some test. Treating "100% coverage" as the goal itself, rather than as a rough proxy for "we've thought about most of this," produces a predictable failure mode: tests written specifically to touch every line, with weak or absent assertions, purely to move the coverage number rather than to actually verify behavior. That's strictly worse than having no test at all for that code, because it looks like safety on a dashboard without providing any.
A more useful frame: chase coverage on the parts of the codebase where a bug would actually be expensive — business logic, anything touching money or user data, code that's changed often and broken before — and don't sweat gaps in trivial one-line wrappers or generated boilerplate where a bug is unlikely and cheap to fix if it happens. A dip in coverage on a critical path is worth investigating; a coverage report sitting at 94% instead of 100% because a handful of __repr__ methods aren't tested usually isn't.