I recently found myself having to unit test some model mixins and I thought I would share the technique I used in case anyone else finds it useful. You could just pick a model which uses the mixin and run the test on instances of that model. But the goal of a mixin is to provide reusable functionality independent of any model. Instead, we create a dummy model we can use for testing.
The model shouldn’t reside in models.py
since we don’t want it in our database. Instead, we create the model dynamically. However, I wanted to test some functionality which requires saving the model to the database. Fortunately, Django can construct the necessary SQL to create and destroy the database table. We simply override setUp and tearDown to do the heavy lifting.
from django.test import TestCase
from django.db import connection
from django.core.management.color import no_style
from django.db.models.base import ModelBase
class ModelMixinTestCase(TestCase):
"""
Base class for tests of model mixins. To use, subclass and specify
the mixin class variable. A model using the mixin will be made
available in self.model.
"""
def setUp(self):
# Create a dummy model which extends the mixin
self.model = ModelBase('__TestModel__'+self.mixin.__name__, (self.mixin,),
{ '__module__': self.mixin.__module__ })
# Create the schema for our test model
self._style = no_style()
sql, _ = connection.creation.sql_create_model(self.model, self._style)
self._cursor = connection.cursor()
for statement in sql:
self._cursor.execute(statement)
def tearDown(self):
# Delete the schema for the test model
sql = connection.creation.sql_destroy_model(self.model, (), self._style)
for statement in sql:
self._cursor.execute(statement)
To make use of this code, just subclass from ModelMixinTestCase
and set the mixin class variable to the model mixin class you wish to test. You’ll then have access to a fully functioning model which uses this mixin via self.model
. Happy testing!