Django Database Testing Unmanaged Tables with Migrations

The answer is here: Models inside tests – Django 1.7 issue.

The problem is that you have some tables that are not managed by Django. (They get called “legacy”, but in my case, they weren’t legacy but data imported from another system.)

The traditional solution to unit testing unmanaged models is to flip the “managed” bit and cause the test runner to create the tables. Example: Django Unit Tests Against Unmanaged Databases.

That doesn’t work with migrations because the unmanaged tables are described in the migration files. You would need to intercept each migration as it’s loaded, and flip the bit.

It appears that this feature didn’t exist when the question above was asked. The Django team created an undocumented feature ‘migrations_not_used_in_tests’ that you use as the migration model, which causes the tester to use syncdb instead.

The tables are created from the models.py descriptions rather than the migration files.

I ended up combining both articles, and created a test_settings.py:

from api.settings import *
from django.test.runner import DiscoverRunner

class UnManagedModelTestRunner(DiscoverRunner):
    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]
        for m in self.unmanaged_models:
            m._meta.managed = True
        super(UnManagedModelTestRunner, self).setup_test_environment(*args, **kwargs)
 
    def teardown_test_environment(self, *args, **kwargs):
        super(UnManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs)
        # reset unmanaged models
        for m in self.unmanaged_models:
            m._meta.managed = False
 
# Set Django's test runner to the custom class defined above
TEST_RUNNER = 'api.test_settings.UnManagedModelTestRunner'

MIGRATION_MODULES = {
    'api':'api.migrations_not_used_in_tests',
    'v1':'v1.migrations_not_used_in_tests'
}

This way, we turn off the migrations, alter the models, and then syncdb before running the tests.

You call this with:

./manage.py test --settings=api.test_settings