pytest-route-coverage
A pytest plugin that tracks HTTP requests made during your test suite and tells you which routes were tested and which weren't.
Supported Frameworks
Only Django is currently supported. You can open an issue (or a PR) if you'd like support for other frameworks.
Installation
pip install pytest-route-coverage
Usage
Run your tests with the --route-coverage flag:
pytest --route-coverage
This writes a .route-coverage JSON file to your project root. To see the report:
route-coverage show
Example output:
============================================================
Routes hit during tests
============================================================
GET /fakes/ [200]x1
Total requests: 1
============================================================
Route coverage by test
============================================================
GET /fakes/
- tests/test_views.py::test_list_fakes
============================================================
Untested routes
============================================================
POST /fakes/ (app/views.py)
Untested: 1 route(s)
By default, all untested routes are shown. Pass --tested-files-only to limit the report to source files that had at least one route tested - useful when running a subset of tests:
route-coverage show --tested-files-only
How it works
The plugin works by injecting a middleware into Django's middleware stack at the start of the test session. This middleware records every request that passes through it — method, path, status code, and which test triggered it.
This means it only captures requests that go through Django's full request/response cycle, i.e., tests that use django.test.Client, DRF's APIClient, or similar. If a test calls a view function directly, that request won't be recorded and the route will show up as untested. This is intentional: a direct function call doesn't exercise routing, middleware, authentication, or any of the other layers a real request would hit.
At the end of the session, the plugin walks Django's URL resolver to build a list of all registered DRF endpoints and writes everything to .route-coverage. The CLI then cross-references the request log against registered routes to find the gaps.
pytest-xdist support
Works out of the box with pytest-xdist. Request logs from all workers are collected on the controller node and merged into a single results file.
pytest --route-coverage -n auto
Parallel and append modes
For CI pipelines that split tests across multiple jobs:
# Each job writes its own file
pytest --route-coverage --route-coverage-parallel
# After all jobs finish, combine them
route-coverage combine
# Or accumulate results incrementally
pytest --route-coverage --route-coverage-append
--route-coverage-parallel writes to .route-coverage.{hostname}.{pid}.{hex} instead of the base file. route-coverage combine merges all suffix files into .route-coverage and cleans up the originals (pass --keep to preserve them).
--route-coverage-append merges new results into an existing .route-coverage file. These two flags are mutually exclusive.
Development
uv sync --group dev
uv run pytest
Running tests
Tests cover Django LTS and latest versions: 4.2, 5.2, and 6.0 (with and without xdist):
uv run tox
License
Apache-2.0
Metadata
Release files for pytest-route-coverage 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pytest_route_coverage-1.0.0.tar.gz | 7.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pytest_route_coverage-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.9 kB
Release files / pytest_route_coverage-1.0.0.tar.gz
| Download URL | pytest_route_coverage-1.0.0.tar.gz |
|---|---|
| Size | 7.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
05b97325f051ebe59405c0cba4301c0a5ea673b8d67dbd550583be8ee1006041
|
|
BLAKE2b-256 checksum How to use checksums |
2bae5a87cb36c5481be2d711a8aa20d82210cac0fa0d88e76fb9cdb1d9de39e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / pytest_route_coverage-1.0.0-py3-none-any.whl
| Download URL | pytest_route_coverage-1.0.0-py3-none-any.whl |
|---|---|
| Size | 10.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6f54ee7bb2a6692054147f053f5defffdf55e95f4334b2d66c378a6c3973c316
|
|
BLAKE2b-256 checksum How to use checksums |
e79aafebe0b76f96ff4b45624416e155655cecf8b78cf254caab575a2c091b55
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|