Search code examples
djangotestingdjango-modelsdjango-testingfactory-boy

Create Temporary Table For Testing Unmanged Model in Django


I've got a django app that has a couple models that read from tables in an unmanaged database.

I'm just trying to create tests appropriately to make sure that the application can be as well tested as possible. I'm using factory_boy to assist with the creation of test data.

One of my unmanaged models looks like this:

class EmpGroup(models.Model):
    id = models.IntegerField(db_column='id', primary_key=True)
    staff_group = models.ForeignKey(
        StaffGroup,
        db_column='staff_group_id',
        on_delete=models.PROTECT
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        db_column='user_id',
        on_delete=models.PROTECT
    )
    location = models.ForeignKey(
        Location,
        db_column='base_loc',
        on_delete=models.PROTECT
    )
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    location_name = models.CharField(max_length=50)

    def __str__(self):
        return f'{self.last_name}, {self.first_name}'

    class Meta(object):
        managed = getattr(settings, 'UNDER_TEST', False)
        db_table = 'control_v_empGroup'

Because that model is unmanaged - there is no migration to tell it to create the table control_v_empGroup when setting up the test DB's. So when I run my tests - I get the the error that the table doesn't exist!

My EmpGroupFactory looks like this:

class EmpGroupFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.EmpGroup

    id = 1
    staff_group = factory.SubFactory(StaffGroupFactory)
    user = factory.SubFactory(UserFactory)
    location = factory.SubFactory(LocationFactory)
    first_name = 'Test'
    last_name = 'Grp'
    location_name = 'Test'

In my settings I have this:

UNDER_TEST = (len(sys.argv) > 1 and sys.argv[1] == 'test')
if UNDER_TEST:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'default-db.sqlite3'),
        },
        'camp': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'camp-db.sqlite3'),
        },
    }
else:
    DATABASES =
    # actual dbs for regular use

I setup the UNDER_TEST so that I can differentiate the databases at test time, from the regular databases in non-text examples. Testing databases are SQLlite.

Is there a way to force Django to setup a table for that particular model when testing, but not during other times?

What is the best way to get unmanaged models under test?


Solution

  • I ended up using Pytest-Django as that testing framework actually allows for doing exactly what I wanted.

    Using the --nomigrations flag, it takes my models which are only managed by django in tests and creates the appropriate table name for them in the test database. Then I can use factory_boy to create mock data and test it up!