AdviceWeb Development

What is the purpose of Code Coverage?

What is the purpose of Code Coverage?

Code coverage is the percentage of your code that runs when you execute your tests. That's it. And that's exactly the problem: a lot of developers confuse "my code ran" with "my code is tested".

What is code coverage?

When you run your unit tests or functional tests, a coverage tool records which lines were executed and which were not. 80% coverage means 20% of your code was never touched.

On a Python project, Coverage.py does this well. You run your tests, it produces a report, you see the gaps. Straightforward.

The catch is that a test can execute code without checking anything. I've seen projects at 95% coverage where half the tests had no assertions at all. The dashboard was green across the board, and bugs still made it to production.

The different types of coverage

There are several ways to measure coverage, and they don't tell the same story.

Line coverage

The most common. How many lines were executed? That's what most tools show by default. A React application tested with Jest might show 90% here, and still have entire if/else blocks where the "else" branch was never tested.

Branch coverage

This one is more interesting. It checks that every if/else, every switch, was taken in all its cases. On payment code, it's the difference between "the validator ran" and "we know what happens when the card is declined".

Path coverage

All possible combinations of branches within a function. The most thorough in theory. In practice, a function with 10 conditions has 1,024 possible paths, so forget about hitting 100%.

Function coverage

Was every function called at least once? That's the bare minimum. Handy for spotting dead code, but it says nothing about what happens inside.

What's the point?

Catching bugs before production

The obvious one. If your authentication component isn't tested, you'll find out when a user can't log in. Not great.

Seeing what nobody understands

Uncovered zones are often the ones the team avoids. Nobody tests them because nobody quite knows what they do. The coverage report makes that visible. API routes sitting at 0%? Either they're unused or they're a liability. Both need attention.

Refactoring without crossing your fingers

When a module has decent coverage, you can rewrite it knowing your tests will warn you if something breaks. Without that, every refactor is a roll of the dice.

Setting it up with Django

Three commands and you're done.

pip install coverage

Run your tests with coverage tracking enabled:

coverage run manage.py test

Check the results:

coverage report

For an HTML report you can browse file by file:

coverage html

Open htmlcov/index.html in your browser.

An example report with Coverage.py

What coverage doesn't tell you

Coverage has a built-in blind spot: it measures what runs, not what's verified. A test that calls a function without checking its return value counts in the stats. It doesn't count in reality.

In practice:

  • A test that checks whether the price including VAT with a 15% discount returns $42.50 is a real test. A test that calls calculate_price() and ignores the result is padding.
  • Double down on the stuff that really hurts when it breaks. Authentication, payments, encryption. A payment module at 50% coverage is a problem waiting for its moment.
  • No need to aim for 100% on a config file or a migration script. Save your energy for the code that has consequences when it gets things wrong.

Coverage is a map. It shows you the terrain. Where you go from there is up to you.

Ready to get started?

From scoping to prototype, to AI integration.

We support your business software projects from start to finish.

Develop my project