8

I have django application with 5 legacy databases. Almost all models are set with the meta attribute managed=False. Since managed=False is set, migrations for each model have been created with the option managed=False. And since, django test runner picks existing migrations for each model to create test tables in test_databases, it simply doesn't create anything. I tried creating test.py settings file with the following workarounds:

from web_services.settings.dev import *
from django.test.runner import DiscoverRunner


class UnManagedModelTestRunner(DiscoverRunner):

    def setup_test_environment(self, *args, **kwargs):
        from django.apps import apps
        self.unmanaged_models = [m for m in apps.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

TEST_RUNNER = 'web_services.settings.test.UnManagedModelTestRunner'

and running python manage.py test --settings=web_services.settings.test. However, it didn't help, since anyway - existing migrations had been already created with managed=False option. Tests seem to be working only after I comment out in my models managed=False, deleted old migrations, created new ones (without managed=False option).

With this, I am quite lost - what is actually a good practice to write tests in my case (multiple legacy databases)? It seems wrong to deal with that hassle of adjusting migrations.

2 Answers 2

10

Here is how I solved my problem for now.

Migrations that are created with managed=False option look like this:

# migrations/0001_initial.py
migrations.CreateModel(
            name='MyModel',
            fields=[
                ('field_id', models.IntegerField(primary_key=True, serialize=False)),
                ('slug', models.CharField(max_length=20, unique=True)),
                ('name', models.CharField(max_length=64)),
            ],
            options={
                'db_table': 'MyModel',
                'managed': False,
            },
        ),

One needs to comment out 'managed': False to allow migrations to be applied. In order not to mess with actual migrations, I have created folder test_migrations and copied there my migrations with 'managed': False commented out:

# test_migrations/0001_initial.py
migrations.CreateModel(
            name='MyModel',
            fields=[
                ('field_id', models.IntegerField(primary_key=True, serialize=False)),
                ('slug', models.CharField(max_length=20, unique=True)),
                ('name', models.CharField(max_length=64)),
            ],
            options={
                'db_table': 'MyModel',
                # 'managed': False,
            },
        ),

Then we need to refer to these migrations during test run. To do that, I have created settings file test.py and put there necessary references. Like this:

from web_services.settings.dev import *


MIGRATION_MODULES = {
    'myapp': 'web_services.apps.myapp.test_migrations',
}

And when running tests, you need to refer to that settings:

python manage.py test --settings=web_services.settings.test

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. I've been thrashing with this for a while. Yours is the only solution that worked (had a problem with importing the settings, but got a workaround for that as well)
Although I don't specially like the need to mantain separate copies of migrations, it's the only working solution I've found so far.
@AmirTugi Thanks for answer. However, you can improve this answer in clean way if you put if 'test' in sys.argv: MIGRATION_MODULES = { 'iop_bypass': 'test_migrations', } this in settings.py Benefit is 1. you dont need new test_settings.py 2. You dont need to run test with extra param 3. You dont get linting problem saying you are doing wildcard import in PEP8
1

after research and read many documents about how to test a legacy read-only database , If you only want to execute the tests in the same legacy database without create a copy of that, the best and simple solution is to setup the same legacy database as a MIRROR in the TEST configuration of the database. I am working with Django 2.2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.