SupercovCompare
← All comparisons

Python · Comparison

pytest-cov vs coverage.py

pytest-cov is a pytest plugin that runs coverage.py, so the numbers match. The real difference is pytest-xdist: plain coverage run reported 0% of lines.

pytest-cov or coverage.py: which should you run?

They do not compete: pytest-cov is a pytest plugin that runs coverage.py for you, so the numbers are the same. Use pytest-cov when you run tests in parallel with pytest-xdist, or want coverage as a pytest flag. Run coverage.py directly when you want one dependency fewer, or your runner is not pytest.

The two commands

pip install coverage
coverage run --branch --source=src -m pytest
coverage report -m
pip install pytest-cov
pytest --cov=src --cov-branch --cov-report=term-missing

Both read the same configuration: [tool.coverage] tables in pyproject.toml, or .coveragerc. Exclusions, fail_under and contexts apply either way.

Same numbers, one real difference

One module and three tests, on coverage.py 7.16.2, pytest-cov 7.1.0, pytest 9.1.1 and Python 3.13.1:

CommandLinesBranches
coverage run -m pytest6/62/2
pytest --cov6/62/2
coverage run -m pytest -n 20/6none
pytest -n 2 --cov6/62/2

With -n 2, pytest-xdist runs the tests in worker processes. Plain coverage run measured only the process that started them and warned “No data was collected”. pytest-cov starts coverage in every worker and combines the results.

coverage.py can do it alone with two settings and one more command. This also gave 6/6:

[run]
parallel = True
patch = subprocess
coverage run -m pytest -n 2
coverage combine
coverage report

What pytest-cov adds, and what it dropped

Its documentation lists four things over coverage run -m pytest: xdist support, combining and reporting in one step, --cov-context=test to record which test ran each line, and the same sys.path as a plain pytest run.

Since 7.0.0 it no longer measures subprocesses your tests start. Use coverage.py’s patch = subprocess for that. It needs coverage.py 7.10.6 or newer.

What neither shows

Both report 100% on this module. Two things were never tested:

  • if signed_in and not expired ran both ways, but no test has a signed-in session that has expired.
  • return user["name"] if user else fallback never returned fallback. coverage.py measures a branch as a line that can jump to more than one next line, and this line has one.

What Supercov adds

npx supercov -- pytest
npx supercov runs latest gaps

Supercov runs your own pytest command in your virtual environment, xdist workers included. On the same module it reported 6/6 lines, 5/6 branches and 1/3 MC/DC conditions, and named both gaps. It records coverage per test.

For other Python tools, see Python coverage: coverage.py, SlipCover, and Supercov.

Example evidence: fixture source, commands and recorded results (JSON). Measured October 12, 2026 with Supercov 4.3.0. These small examples are not a performance benchmark or a general conformance test.