Opened 4 years ago

Closed 4 years ago

#28400 closed Bug (invalid)

TransactionTestCase will truncate data created from data migration

Reported by: Jared Mackey Owned by: nobody
Component: Testing framework Version: 1.11
Severity: Normal Keywords: tests, data-migrations
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Jared Mackey)

Data migrations that create data in the database do not persist after running tests that inherit from TransactionTestCase. The first test that runs on the database works as expected but subsequent tests do not. I am filling as a bug as I would expect that data created before tests are ran would persist a transaction rollback during the test cases. A possible solution to this is to re-run data only migrations after truncating the tables.

Here is an example migration:

def add_group_permissions(apps, schema_editor):
    for app_config in apps.get_app_configs():
        app_config.models_module = True
        create_permissions(app_config, verbosity=0)
        app_config.models_module = None

    Group = apps.get_model('auth', 'Group')
    Permission = apps.get_model('auth', 'Permission')

    group, _ = Group.objects.get_or_create(name='demo_group')
    group.permissions.clear()
    permission = Permission.objects.get(codename='existing_permission')
    group.permissions.add(permission)


class Migration(migrations.Migration):

    dependencies = [ ]

    operations = [
        migrations.RunPython(add_group_permissions, reverse_code=migrations.RunPython.noop),
        migrations.RunPython(lambda apps, schema_editor: ContentType.objects.clear_cache()),   # hack to get the ContentType cache to clear
    ]

Here is a test case that will prove that the second test to run will fail with django.contrib.auth.models.DoesNotExist: Group matching query does not exist.

class TestGroupsExist(TransactionTestCase):
    """ One of these tests will fail. Which one depends on which one the test runner runs first. The second one to run will fail. """ 
    def test_group_exists_1(self):
         self.assertIsNotNone(Group.objects.get_by_natural_key('demo_group'))

    def test_group_exists_2(self):
         self.assertIsNotNone(Group.objects.get_by_natural_key('demo_group'))

The following log is found after the first test is ran.

TRUNCATE ... "auth_group_permissions", "auth_group", ...;; args=None

Change History (2)

comment:1 Changed 4 years ago by Jared Mackey

Description: modified (diff)

comment:2 Changed 4 years ago by Tim Graham

Resolution: invalid
Status: newclosed

This is as documented:

Any initial data loaded in migrations will only be available in TestCase tests and not in TransactionTestCase tests ... Django can reload that data for you on a per-testcase basis by setting the serialized_rollback option to True in the body of the TestCase or TransactionTestCase, but note that this will slow down that test suite by approximately 3x.

Note: See TracTickets for help on using tickets.
Back to Top