Automatic admin smoke-test coverage for Django projects. Better than nothing.
Admin pages break quietly. A renamed field in list_display, a
get_queryset that blows up on a related lookup, a permission tweak that
locks out the wrong people — none of it shows up until someone opens the page.
This package asserts that every ModelAdmin you register still serves its
changelist, add and change views, as part of your test run, under either
manage.py test or pytest. No test per model.
pip install django-admin-tests
Requires Python 3.10+ and Django 4.2+. The only runtime dependency is Django itself.
Put this in any test module your runner already collects:
from django_admin_tests import testcases
class AdminSmokeTest(testcases.AdminSmokeTestCase):
pass
That's the whole setup. Run your tests as usual:
pytest
# or
python manage.py test
The examples import the module, not the class, on purpose. Test
discovery scans the whole module namespace for TestCase subclasses, so
importing the name directly collects the un-customized base class as a test of its
own, alongside your subclass:
from django_admin_tests.testcases import AdminSmokeTestCase # base class runs too
class AdminSmokeTest(AdminSmokeTestCase):
pass
Subclassing is also how you adjust behavior:
from django_admin_tests import testcases
from myapp.models import InternalReport, LegacyThing
class AdminSmokeTest(testcases.AdminSmokeTestCase):
# Admins that intentionally deny access:
model_allowed_status_codes = {InternalReport: {403}}
# Admins to skip entirely:
excluded_models = {LegacyThing}
| Attribute | Default | Purpose |
|---|---|---|
admin_site | admin.site | Test a custom AdminSite |
allowed_status_codes | {200} | Globally accepted statuses |
model_allowed_status_codes | {} | Per-model status overrides |
excluded_models | None | Models to skip entirely |
user_factory | None | Supply the authenticating user |
If you use pytest, the bundled plugin can collect the smoke tests without you writing a test file at all. It is opt-in — installing this package will never silently add tests to your suite:
# pyproject.toml
[tool.pytest.ini_options]
django_admin_tests_auto = true
There's no class to subclass in this mode, so configure it through Django settings instead.
| Setting | Default | Purpose |
|---|---|---|
ADMIN_TESTS_ALLOWED_STATUS_CODES | {200} | Globally accepted statuses |
ADMIN_TESTS_MODEL_ALLOWED_STATUS_CODES | {} | Per-model overrides, keyed "app_label.ModelName" |
ADMIN_TESTS_EXCLUDE | [] | Models to skip, 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.
To load a change view, there has to be something to change. An instance is resolved per model in this order:
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:
from django_admin_tests import register_factory
from myapp.models import Tricky
def make_tricky():
return Tricky.objects.create(...)
register_factory(Tricky, make_tricky)
Call it anywhere that runs at startup — an AppConfig.ready(), or
conftest.py. The auto-builder is written in-house and pulls in no
third-party dependency.
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(testcases.AdminSmokeTestCase):
user_factory = staticmethod(my_superuser_factory)
The tests are tagged django_admin_tests:
python manage.py test --exclude-tag=django_admin_tests
pytest -m "not django_admin_tests"
save() or
clean() requirements. Use register_factory for those.
AUTH_USER_MODEL support is the user_factory hook only;
there's no auto-detection of required fields.