testing admin.ModelAdmin in django
Asked Answered
L

4

74

I am trying to find out the best way for testing admin.ModelAdmin in admin.py. Specifically I am overriding the save_model() function which I want to test. From the research I have done, the only solution I have found was writing a request/response test and then query the database.

Lynnette answered 27/6, 2011 at 20:21 Comment(0)
M
64

Check out Django's ModelAdminTests for examples.

Morganstein answered 27/6, 2011 at 20:39 Comment(1)
Nice referencing :)Truda
C
86

As suggested in Udi's answer, we can study Django's own ModelAdmin tests, to determine the basic ingredients for a ModelAdmin test. Here's a summary:

Basic ingredients

In addition to the Django TestCase stuff, the basic ingredients are:

  1. An instance of AdminSite:

     from django.contrib.admin.sites import AdminSite
    
  2. Your model class and corresponding ModelAdmin (sub)class:

     from my_app.models import MyModel
     from my_app.admin import MyModelAdmin
    
  3. Optionally, depending on your needs, a (mock) request and/or form.

Recipe

The first two ingredients are required to create an instance of your (custom) ModelAdmin:

my_model_admin = MyModelAdmin(model=MyModel, admin_site=AdminSite())

Based on the ModelAdmin source, the default save_model implementation only requires an instance of your model, so it can be called, for example, as follows:

my_model_admin.save_model(obj=MyModel(), request=None, form=None, change=None)
# some test assertions here

It all depends on what your save_model does, and what you want to test. Suppose your save_model checks user permissions, then you would need to provide a request (i.e. the third ingredient) with a valid user, in addition to the model instance:

from unittest.mock import Mock

...

my_user = User.objects.create(...)
my_model_admin.save_model(
    obj=MyModel(), request=Mock(user=my_user), form=None, change=None
)
# some test assertions here

Here we use unittest.mock.Mock to create a mock-request. Based on the Django test source, a minimal request consists of a Python object with a user attribute. The user attribute may refer to a mock user, or an actual instance of your AUTH_USER_MODEL, depending on your needs. An alternative would be to use django.test.RequestFactory.

This basic approach applies to the other ModelAdmin methods as well.

Chesterfieldian answered 13/2, 2019 at 10:24 Comment(1)
Thanks for the detailed answer. I got lots of great clues and boilerplate code from this.Tharp
M
64

Check out Django's ModelAdminTests for examples.

Morganstein answered 27/6, 2011 at 20:39 Comment(1)
Nice referencing :)Truda
R
6

You can specify custom modelform for modeladmin then simply test this modelform ;)

https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form

forms

class SomeModelForm(forms.ModelForm):
    class Meta:
        model = SomeModel

admin

class SomeModelAdmin(admin.ModelAdmin):
    form = SomeModelForm


admin.site.register(SomeModel, SomeModelAdmin)

tests

class TestSomeModel(TestCase):
    def test_form(self):
        form = SomeModelForm(**kwargs)
        self.assertTrue(form.is_valid())
        # ...
Retha answered 21/5, 2015 at 8:58 Comment(1)
Keep in mind that this doesn't reliably tests saving the object.Lindemann
C
0

To test if the search does not lead to server errors (i.e. because search_fields are not correct) you can use the following code:

from django.contrib import admin
from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse


class TestModelAdmins(TestCase):
    def test_search_fields(self):
        user_1 = User(
            username="user1",
            first_name="User",
            last_name="One",
            email="[email protected]",
            password="superSecurePasswordFromStackoverflow",
            is_superuser=True,
            is_staff=True,
        )
        user_1.full_clean()
        user_1.save()
        self.client.force_login(user_1)
        for model_class, admin_class in admin.site._registry.items():
            with self.subTest(model_class._meta.model_name):
                path = reverse("admin:%s_%s_changelist" % (model_class._meta.app_label, model_class._meta.model_name))
                response = self.client.get(path + "?q=blub")
                self.assertEqual(response.status_code, 200)
Crasis answered 14/3, 2023 at 19:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.