Skip to main content

Coverage & CI Integration

Code coverage measures which lines of your source code are executed during tests. A high coverage percentage doesn't guarantee correctness, but a low one reveals untested paths.

pytest-cov

pip install pytest-cov

Run tests with coverage:

pytest --cov=myapp tests/

Generate an HTML report:

pytest --cov=myapp --cov-report=html tests/
# open htmlcov/index.html

Output:

---------- coverage: platform linux ----------
Name                  Stmts   Miss  Cover
-----------------------------------------
myapp/auth.py            42      3    93%
myapp/models.py          61      8    87%
myapp/utils.py           28      0   100%
-----------------------------------------
TOTAL                   131     11    92%

Fail Below a Threshold

pytest --cov=myapp --cov-fail-under=80 tests/

The command exits with a non-zero code if coverage drops below 80% — CI picks this up as a failure.

.coveragerc Configuration

# .coveragerc
[run]
source = myapp
omit =
    myapp/migrations/*
    myapp/tests/*
    */conftest.py

[report]
fail_under = 80
show_missing = true

Or in pyproject.toml:

[tool.coverage.run]
source = ["myapp"]
omit = ["myapp/migrations/*"]

[tool.coverage.report]
fail_under = 80
show_missing = true

GitHub Actions Workflow

# .github/workflows/pytest.yml
name: Pytest

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: |
          pip install -r requirements.txt
          pip install pytest pytest-cov pytest-mock

      - name: Run tests with coverage
        run: pytest --cov=myapp --cov-report=xml --cov-fail-under=80

      - name: Upload coverage report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: coverage-report
          path: htmlcov/

      - name: Upload to Codecov
        uses: codecov/codecov-action@v4
        with:
          file: coverage.xml

Coverage Report Visualiser

Coverage report simulation
Ctrl+Enter
HTML
CSS
JS
Preview

Useful pytest Flags Summary

pytest -v                          # verbose  show test names
pytest -s                          # show print() output
pytest -x                          # stop on first failure
pytest --tb=short                  # shorter tracebacks
pytest --lf                        # rerun last failed tests only
pytest -n auto                     # parallel (requires pytest-xdist)
pytest --cov=myapp --cov-fail-under=80

pyproject.toml One-stop Config

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v --tb=short --cov=myapp --cov-fail-under=80"

With this in place, just running pytest applies all your standard flags.