SupercovCompare
← All comparisons

Python · Comparison

Python coverage: coverage.py, SlipCover, and Supercov

Compare Python coverage tools: coverage.py with pytest-cov, SlipCover, and Supercov. See per-test contexts, MC/DC, and assertion coverage side by side.

Start with pytest-cov for line and branch coverage

For an existing pytest project, coverage.py with pytest-cov is a straightforward starting point. pytest-cov connects coverage.py to pytest; it is not a second measurement engine.

Install it in your project’s Python environment, then measure your source:

python -m pip install pytest-cov
python -m pytest --cov=src --cov-branch --cov-report=term-missing

Replace src with your package or source directory. The report lists missed lines and partial branches. coverage.py’s branch guide explains how it records transitions between lines.

To associate execution with individual pytest tests, add --cov-context=test. pytest-cov supports per-test contexts, including setup, run and teardown. Supercov is not unique simply because it connects code with tests.

If your project uses unittest, you can keep that runner:

python -m coverage run --branch --source=src -m unittest discover
python -m coverage report -m

Where SlipCover fits

SlipCover is an alternative line and branch collector. It can launch pytest without a separate pytest coverage plugin:

python -m pip install slipcover
python -m slipcover --branch --source src -m pytest

Its documentation explains the collection approach and supported environments. If coverage overhead is your problem, compare it on your own suite with the same Python version, source scope and outputs. The small example below is not a speed test.

Run the same pytest suite with all three tools

Download the comparison and open its python folder. Use CPython 3.9 or newer; the recording used 3.13.1. Create a virtual environment and install the pinned packages:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt

On Windows, activate with .venv\\Scripts\\Activate.ps1 instead. The requirements file belongs to this downloadable example, not to your existing project.

Its source is:

def checkout(signed_in, expired, price, quantity):
    if signed_in and not expired:
        total = price * quantity
        return {"status": "confirmed", "total": total}
    return {"status": "denied", "total": 0}

Two pytest tests check the returned status for a valid session and a signed-out visitor. Neither checks an expired session or the calculated amount.

python -m pytest --cov=src --cov-branch --cov-context=test --cov-report=term-missing
python -m slipcover --branch --source src -m pytest
supercov -- python -m pytest
supercov runs latest

The coverage.py report includes:

Name             Stmts   Miss Branch BrPart  Cover   Missing
------------------------------------------------------------
src/session.py       5      0      2      0   100%
------------------------------------------------------------
TOTAL                5      0      2      0   100%

Here are the recorded results. coverage.py and SlipCover ran on September 14, 2026; Supercov’s runs were repeated with 2.0.0 on September 25 and matched. Every run uses the same source and pytest tests.

ReportLinesBranchesMC/DC
coverage.py 7.16.0 through pytest-cov 7.1.0100% (5/5)100% (2/2)Not reported
SlipCover 1.1.0100% (5/5)100% (2/2)Not reported
Supercov 2.0.0 wrapping pytest100% (5/5)100% (6/6)50% (1/2)

The tools use different branch models, hence the different denominators. That does not make one branch count more correct. MC/DC supplies a separate measurement: whether each condition independently changes the decision.

Find the missing expiry test

Query the checkout decision:

supercov runs latest decision src/session.py:2

The output includes:

signed_in and not expired
C1 covered: signed_in
C2 MISSING: not expired
confidence executed
vectors:
  TT -> T  tests=1 confidence=executed
  F- -> F  tests=1 confidence=executed

The signed-out test reaches the denied branch without evaluating the expiry condition. A signed-in customer with an expired session is the missing case:

def test_rejects_an_expired_session():
    assert checkout(True, True, 25, 2)["status"] == "denied"

With that third case, the valid-session test and expired-session test show the expiry condition changing the result. The MC/DC guide walks through the comparison.

Check the amount, not just the status

A returned status does not establish that the total is right. The original tests still pass if the calculation subtracts 1 from the answer. A stronger assertion in the valid-session test is:

assert checkout(True, False, 25, 2) == {"status": "confirmed", "total": 50}

The download includes the completed suite in completed-tests.txt. Replace tests/test_session.py with its contents and rerun the same commands.

CheckStarter testsCompleted tests
Tests against the original codePass: 2 testsPass: 3 tests
Native line and branch coverage100%100%
MC/DC50% (1/2)100% (2/2)
Remove the expiry guardStill passFail
Subtract 1 from the totalStill passFail

Both faults were run separately. This demonstrates two specific missing checks, not a general mutation score. The recording includes commands, full output, source and tests.

Assertions were not assessed here (the comparison was recorded with Supercov 2.0), so it reports no assertion-coverage percentage. Assertion coverage is a separate step: runs latest assertions assess asks Jev which executed statements each test would catch a change to.

Which tool should you keep?

Use coverage.py and pytest-cov when line, branch and test-context reports answer your question. Consider SlipCover when evaluating collection overhead. Supercov adds independent-condition gaps and an assertion-review workflow without replacing pytest.

Coverage features
Featurecoverage.py7.16.0SlipCover1.1.0Supercov2.0.0
Code quality scoringNot built inNot built inSupported
Security reviewNot built inNot built inSupported
Line coverageSupportedSupportedSupported
Branch coverageSupportedSupportedSupported
MC/DCNot built inNot built inSupported
Per-test coverageSupportedNot built inSupported
Assertion coverageNot built inNot built inSupported
ReportsSupportedNot built inSupported

✓ Supported · × Not built in. Standard coverage workflows in the versions shown; custom plugins are outside this table.

Supercov measures CPython 3.9 and newer. pytest-cov uses coverage.py; enable test contexts for per-test coverage.

Per-test coverage means individual tests, not just test files. Supercov needs a supported runner. Assertion coverage is Jev’s judgment, test by test, of whether changing each executed statement would make the test fail; it is not a mutation score or a correctness guarantee. Security review comes from Supercov’s Jev checks; reports means a browsable HTML report from the tool itself.

Supercov measures CPython 3.9 or newer. See the Python installation guide. It is not the only Python MC/DC option: pymcdc is a dedicated analyzer.

None of these coverage percentages prove that the application meets its requirements. For checks outside source coverage, compare QA tools for coding agents.

Example evidence: source, commands and full results (JSON) · runnable examples (ZIP). Measured September 14, 2026; Supercov runs repeated with 2.0.0 on September 25, unchanged. Same-runner fixtures, not a performance benchmark or a general conformance test.

Feature sources