testing admin.ModelAdmin in django

DjangoUnit TestingDjango Admin

Django Problem Overview


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.

Django Solutions


Solution 1 - Django

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 pass a request (i.e. the third ingredient) with a valid user, in addition to the model instance:

super_user = User.objects.create_superuser(username='super', email='[email protected]',
                                           password='pass')
my_model_admin.save_model(obj=MyModel(), request=MockRequest(user=super_user),
                          form=None, change=None)
# some test assertions here

An example of the MockRequest is defined below. 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.

class MockRequest(object):
    def __init__(self, user=None):
        self.user = user

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

Solution 2 - Django

Check out Django's ModelAdminTests for examples.

Solution 3 - Django

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())
        # ...

Solution 4 - Django

I had a similar problem so I wrote a tiny little helper here: https://github.com/metzlar/djest

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioninstigatorView Question on Stackoverflow
Solution 1 - DjangodjvgView Answer on Stackoverflow
Solution 2 - DjangoUdiView Answer on Stackoverflow
Solution 3 - DjangomadzohanView Answer on Stackoverflow
Solution 4 - Djangouser199977View Answer on Stackoverflow