Smoke test Django Admin views

Having tests is awesome, having to maintain an extensive test suite is painful, so every once in a while I try to ease that pain with normalization, standardization and automation — even in test generation. I love @pytest.mark.parametrize for the possibilities it gives me in that area.

Testing Admin Views is a little bit too much, right? They are easy to create, and most of the times check command will catch any stupid mistakes as having a typo in field name. You do have check command ran during CI right?

Every once in while I got in trouble with Admin Views that passed the usual check, when actual data was involved in some edge cases, one of CRUD views did return HTTP 500. So I came up with admin smoke tests that are extremely easy to use if you have test model factories.

Here you go:

import logging

import pytest
from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.shortcuts import resolve_url

from . import factories

log = logging.getLogger(__name__)

ADMIN_FACTORIES = (
    factories.AccountFactory,
    factories.AccountGroupFactory,
    factories.BudgetFactory,
    factories.ApplicationFactory,
)


# noinspection PyUnusedLocal,PyMethodMayBeStatic,PyProtectedMember
@pytest.mark.django_db
@pytest.mark.parametrize(
    "factory", ADMIN_FACTORIES
)
class AdminTests(object):
    def test_changelist(self, factory, admin_client):
        factory()
        url = resolve_url(admin_urlname(factory._meta.model._meta, 'changelist'))
        response = admin_client.get(url)
        assert response.status_code == 200

    def test_change(self, factory, admin_client):
        item = factory()
        url = resolve_url(admin_urlname(factory._meta.model._meta, 'change'), item.pk)
        response = admin_client.get(url)
        assert response.status_code == 200

    def test_add(self, factory, admin_client):
        url = resolve_url(admin_urlname(factory._meta.model._meta, 'add'))
        response = admin_client.get(url)
        assert response.status_code == 200

    def test_delete(self, factory, admin_client):
        item = factory()
        url = resolve_url(admin_urlname(factory._meta.model._meta, 'delete'), item.pk)
        response = admin_client.get(url)
        assert response.status_code == 200

Having another model CRUD admin view set under coverage is extremely easy to do, just append the new factory to the list and your are set.

Obviously this just tests if views are loading. Having them perform actual CRUD operation is little bit more complicated but definitely doable. You need standardize model–to-post-data. You can start with Django’s own model_to_dict – with some tweaks supporting your use cases.

Anyway, it’s a win to have this easy to test just HTTP 200 and with almost no maintenance cost.

Leave a Reply

Back to Top