Unit-testing unmanaged Django models

Posted on Sat 31 August 2013 in Tech

Say you have an app with a set of models that aren't being managed by Django, you're going to run into trouble when it comes time to run unit-tests against these. What I mean is if in the model meta you have something like this

 app_label = 'your_app_label'
 managed = False
 db_table = u'your_table_name'

If you run unit-tests against these models the trouble occurs because django will ignore this model when creating tables in the test database and you'll get a relation not defined error for 'your_table_name'. The solution to this is to create an app specific TestRunner that will over-ride this setting and temporarily allow Django to manage your models, just for testing purposes.

from django.test.simple import DjangoTestSuiteRunner

class ManagedModelTestRunner(DjangoTestSuiteRunner):
 """
 Test runner that automatically makes all unmanaged models in your Django
 project managed for the duration of the test run, so that one doesn't need
 to execute the SQL manually to create them.
 """
 def setup_test_environment(self, *args, **kwargs):
    from django.db.models.loading import get_models
    self.unmanaged_models = [m for m in get_models() if not m._meta.managed and m._meta.app_label is 'your_app_label']
    m._meta.managed = True
    super(ManagedModelTestRunner, self).setup_test_environment(*args,
 **kwargs)

def teardown_test_environment(self, *args, **kwargs):
    super(ManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs)
    # reset unmanaged models
    m._meta.managed = False

This code was lovingly taken from here and extending very slightly to only include models that exist under the my_app_label app. I don't want my app's test to go fudging around with others, unless it's needed.

To then run tests with this testrunner, create a test_settings.py that looks something like this. This which basically tells Django to import your existing settings but to use your newly created TestRunner

from settings import *

TEST_RUNNER = 'your_app_label.scripts.testrunner.ManagedModelTestRunner'
./manage.py test your_app_label settings=you_app_label.settings.test_settings