---
title: "Chasing 100% Coverage With Tests That Do Nothing"
description: "Test coverage is not a target, it's a byproduct. The cost of tests written to push the number up that catch no bugs at all"
url: https://sade.dev/en/journal/a-lean-testing-culture/
lang: en
author: "Muhammet Şafak"
published: 2026-10-17
section: Journal
tags: ["testing","quality","opinion"]
summary: "Coverage measures only that a line ran, not that it was verified; once it becomes a target, people write the cheapest tests that raise the number and catch no bugs. A test is worth the bugs it catches: test the behavior that matters and let coverage arrive as a by-product. Spend the test budget on complex logic, code that handles money and places that have failed before."
---

# Chasing 100% Coverage With Tests That Do Nothing

> Coverage measures only that a line ran, not that it was verified; once it becomes a target, people write the cheapest tests that raise the number and catch no bugs. A test is worth the bugs it catches: test the behavior that matters and let coverage arrive as a by-product. Spend the test budget on complex logic, code that handles money and places that have failed before.

I saw a pull request: forty new tests, all serving a single purpose — pushing coverage to 100%. Most of them called a getter and verified that the value just set came back. Coverage turned green. The number of bugs those forty tests would catch: zero.

Test coverage is a useful number — until you turn it into a target.

## What coverage measures, and what it doesn't

Coverage measures one thing: which lines of code **run** while the tests execute. What it doesn't measure matters far more: whether those lines are actually **verified**.

A line counts as "covered" even by a test with no meaningful `assert`. The code runs, the test is green, but nobody has checked whether the code behaves correctly. Coverage can't see the difference between code that runs and code that's verified.

## The wrong metric rewards the wrong test

Once coverage becomes a target, human behavior is predictable: people write the tests that raise the number by the cheapest route.

- Getter/setter tests — testing code that has no logic.
- Tests that verify a mock was called — an interaction, not a real result.
- Tests whose `assert` is meaningless, which only say "it didn't blow up".

These raise the coverage number and catch no bugs. Worse: a green 100% gives the team false confidence. Code that's assumed to be tested has merely been executed.

## The measure of a good test

A test's value lies not in the line it covers but in the bug it catches. A simple check: deliberately break the logic of the code — turn a `+` into a `-`, invert a condition. A good test goes red. If it doesn't, that test isn't verifying anything.

The systematic form of this idea is mutation testing: the tool breaks the code in small ways and measures whether your tests catch it. Coverage says "did the line run"; mutation testing says "was the line actually tested".

## Coverage is a byproduct

The right order is the reverse: test the behavior that matters first, and let coverage rise as a **byproduct**. Chase the number and you write tests that do nothing; chase the behavior and coverage comes anyway — and the coverage you get is real.

100% is not a target. A critical path that's never tested can exist even in a 100% codebase; conversely, a system with 75% coverage may be solidly testing every risky path.

## Where to spend the testing budget

Writing tests is also writing code; it has a limited budget. Spend that budget according to risk:

- Complex logic, code that handles money, calculations.
- Edge cases — boundary values, empty input, concurrency.
- Places that have broken before — if a bug came out of there once, it will again.

Testing trivial, logicless code wastes the budget. The "the test setup is longer than the test itself" sign I mentioned in [signals that a system has grown too complex](/en/journal/signals-of-an-over-complex-system) connects here too: if a test is very hard to write, the problem isn't the test, it's that the code under test is too tightly coupled.

---

A coverage percentage is not a source of confidence; it's only an observation. Confidence comes from the bugs your tests catch — not the number they chase.

Aim not for the number, but for the test that goes red when the code is wrong.

## Sources

- [Test Coverage](https://martinfowler.com/bliki/TestCoverage.html) — martinfowler.com
