Testing django application with several legacy databases
Asked Answered
H

2

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.

Hawes answered 2/5, 2016 at 15:41 Comment(0)
H
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

Hawes answered 5/5, 2016 at 20:56 Comment(3)
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)Weapon
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.Nystagmus
@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 PEP8Degradation
G
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

Gat answered 11/2, 2023 at 0:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.