Skip to main content

django-admin-tests

CI

Automatic admin smoke-test coverage for Django projects.

📖 Documentation

Every ModelAdmin you register gets its changelist, add and change views asserted to return 200 — as part of your test run, under either manage.py test or pytest. Admin pages break quietly: a renamed field in list_display, a get_queryset that blows up on a related lookup, a permission tweak. This catches that without you writing a test per model.

You get one test method per model and view, named after the model, so a broken admin fails under its own name rather than inside a shared loop:

test_admin_smoke_shop_product_changelist
test_admin_smoke_shop_product_add
test_admin_smoke_shop_product_change
test_admin_smoke_blog_article_changelist
...

Install

pip install django-admin-tests

Requires Python 3.10+ and Django 4.2+.

Usage

There are two ways in. Both run under either test runner.

Option 1 — subclass it (works everywhere)

Put this in any test module your runner already collects:

from django_admin_tests.testcases import AdminSmokeTestCase


class AdminSmokeTest(AdminSmokeTestCase):
    pass

That's it. Subclassing is also how you customize behavior:

from django_admin_tests.testcases import AdminSmokeTestCase

from myapp.models import InternalReport, LegacyThing


class AdminSmokeTest(AdminSmokeTestCase):
    # Admins that intentionally deny access:
    model_allowed_status_codes = {InternalReport: {403}}
    # Admins to skip entirely:
    excluded_models = {LegacyThing}

Note: import the module, not the class, if you'd rather the base class not be collected as a test in its own right. Test discovery scans the whole module namespace for TestCase subclasses, so from django_admin_tests.testcases import AdminSmokeTestCase makes the un-customized base class run too. from django_admin_tests import testcases and then testcases.AdminSmokeTestCase avoids that.

Option 2 — pytest plugin (no test file needed)

If you use pytest, the bundled plugin can collect the smoke tests without you writing anything. It's opt-in — installing this package will never silently add tests to your suite:

# pyproject.toml
[tool.pytest.ini_options]
django_admin_tests_auto = true

Since there's no class to subclass in this mode, configure it through Django settings instead (see below).

Settings

Setting Default Purpose
ADMIN_TESTS_ALLOWED_STATUS_CODES {200} Globally accepted response statuses
ADMIN_TESTS_MODEL_ALLOWED_STATUS_CODES {} Per-model overrides, keyed "app_label.ModelName"
ADMIN_TESTS_EXCLUDE [] Models to skip entirely, same key format
# settings.py
ADMIN_TESTS_MODEL_ALLOWED_STATUS_CODES = {"myapp.InternalReport": [403]}
ADMIN_TESTS_EXCLUDE = ["myapp.LegacyThing"]

Resolution order is class attribute → Django setting → built-in default, so a subclass always wins over settings.

Excluded models keep their test methods and report as skipped, so an opt-out stays visible in your output rather than looking like a model that was never covered.

Running one model's tests

Because each model gets its own methods, you can iterate on a single admin without re-running the rest:

pytest -k shop_product
python manage.py test myapp.tests.AdminSmokeTest.test_admin_smoke_shop_product_changelist

You can also override a single model's check by defining a method with the generated name — yours wins, and the generated one isn't installed:

class AdminSmokeTest(testcases.AdminSmokeTestCase):
    def test_admin_smoke_shop_product_changelist(
        self,
    ): ...  # your own assertions for this one admin

Change views need an object

To load a change view, there has to be something to change. An instance is resolved per model in this order:

  1. A factory you registered for that model
  2. Any existing row
  3. A minimal instance built automatically from the model's fields

If none of those work — most often a required self-referential or circular foreign key — that model's change-view check is skipped with a warning, not failed. Register a factory to cover it:

# In your AppConfig.ready(), conftest.py, or anywhere that runs at startup
from django_admin_tests import register_factory

from myapp.models import Tricky


def make_tricky():
    return Tricky.objects.create(...)


register_factory(Tricky, make_tricky)

The auto-builder is in-house and dependency-free — installing this package pulls in nothing but Django.

Turning it off

The tests are tagged django_admin_tests:

python manage.py test --exclude-tag=django_admin_tests
pytest -m "not django_admin_tests"

Custom user models

The test client authenticates as a superuser it creates itself, using the default User fields. If your AUTH_USER_MODEL needs something else, supply a factory:

class AdminSmokeTest(AdminSmokeTestCase):
    user_factory = staticmethod(my_superuser_factory)

Custom admin sites

from myproject.admin import my_site


class AdminSmokeTest(AdminSmokeTestCase):
    admin_site = my_site

Known limitations

  • Models whose change view can't be instantiated are skipped with a warning rather than failed. That's deliberate — a smoke test shouldn't fail because a model is awkward to construct — but it does mean an un-covered model can go unnoticed. The warning names it.
  • The auto-builder doesn't try to satisfy custom save()/clean() requirements. Use register_factory for those.
  • Custom AUTH_USER_MODEL support is the user_factory hook only; there's no auto-detection of required fields.
  • Many-to-many fields aren't populated (they aren't needed for the views to render).
  • The admin registry is read when the test class is created, so admins registered after that aren't covered. In practice registration happens during app loading, which always precedes test module import.
  • manage.py test --parallel won't spread these across processes. Django distributes work per TestCase class, and all the generated methods live on one class, so the run stays single-process.
  • Two models whose app label and model name differ only in where the underscore falls (foo_bar.baz vs foo.bar_baz) would generate the same method name. That raises ImproperlyConfigured rather than silently dropping one — exclude one of them to proceed.

Releasing

Versions are derived from git tags via hatch-vcs — nothing to bump in pyproject.toml. To cut a release:

  1. In CHANGELOG.md, retitle ## [Unreleased] to ## [X.Y.Z] - YYYY-MM-DD and add a fresh empty ## [Unreleased] section above it.
  2. Commit that change, then tag the commit with the bare version — no v prefix — and push both: git tag X.Y.Z && git push origin master --tags.
  3. Pushing the tag triggers .github/workflows/release.yml, which builds the sdist/wheel, publishes to PyPI (via Trusted Publishing), and creates a GitHub Release using that CHANGELOG section as its notes.

License

MIT — see LICENSE.

Metadata

Release files for django-admin-tests 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-admin-tests 0.2.0
File Size Uploaded Provenance Actions
django_admin_tests-0.2.0.tar.gz 30.3 kB With provenance Details for django_admin_tests-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-admin-tests 0.2.0
File Interpreter ABI Platform Actions
django_admin_tests-0.2.0-py3-none-any.whl Python 3 none any Details for django_admin_tests-0.2.0-py3-none-any.whl

Total release size: 47.2 kB

Release files / django_admin_tests-0.2.0.tar.gz

Download URL django_admin_tests-0.2.0.tar.gz
Size 30.3 kB
Tags Source
SHA-256 checksum
How to use checksums
f4bdd1ad45dc3370093d842174e71bef5dcdb5a512aa188556f68b2315cf7b23
BLAKE2b-256 checksum
How to use checksums
e93ad61486b3ab99bea4d2e13336c4a93c883eb3faaf9f20ba2f1a909cee882c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release files / django_admin_tests-0.2.0-py3-none-any.whl

Download URL django_admin_tests-0.2.0-py3-none-any.whl
Size 17.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7114222074e416425fe1037ee7b848af772204cc8ac92d0967bb22237b5f9275
BLAKE2b-256 checksum
How to use checksums
98be5f179669348f21daec54b1215c0123ee4d1e590e384ed6f5c8f3b3b194d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Security for django-admin-tests 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_admin_tests-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page