Something-driven development

Software development thoughts around Ubuntu, Python, Golang and other tools

Testing django migrations

with 8 comments

A number of times over the past few years I’ve needed to create some quite complex migrations (both schema and data) in a few of the Django apps that I help out with at Canonical. And like any TDD fanboy, I cry at the thought of deploying code that I’ve just tested by running it a few times with my own sample data (or writing code without first setting failing tests demoing the expected outcome).

This migration test case helper has enabled me to develop migrations test first:

class MigrationTestCase(TransactionTestCase):
    """A Test case for testing migrations."""

    # These must be defined by subclasses.
    start_migration = None
    dest_migration = None
    django_application = None

    def setUp(self):
        super(MigrationTestCase, self).setUp()
        migrations = Migrations(self.django_application)
        self.start_orm = migrations[self.start_migration].orm()
        self.dest_orm = migrations[self.dest_migration].orm()

        # Ensure the migration history is up-to-date with a fake migration.
        # The other option would be to use the south setting for these tests
        # so that the migrations are used to setup the test db.
        call_command('migrate', self.django_application, fake=True,
        # Then migrate back to the start migration.
        call_command('migrate', self.django_application, self.start_migration,

    def tearDown(self):
        # Leave the db in the final state so that the test runner doesn't
        # error when truncating the database.
        call_command('migrate', self.django_application, verbosity=0)

    def migrate_to_dest(self):
        call_command('migrate', self.django_application, self.dest_migration,

It’s not perfect – schema tests in particular end up being quite complicated as you need to ensure you’re working with the correct orm model when creating your test data – and you can’t use the normal factories to create your test data. But it does enable you to write migration tests like:

class MyMigrationTestCase(MigrationTestCase):

    start_migration = '0022_previous_migration'
    dest_migration = '0024_data_migration_after_0023_which_would_be_schema_changes'
    django_application = 'myapp'

    def test_schema_and_data_updated(self):
        # Test setup code


        # Assertions

which keeps me happy. When I wrote that I couldn’t find any other suggestions out there for testing migrations. A quick search now turns up one idea from André (data-migrations only),  but nothing else substantial. Let me know if you’ve seen something similar or a way to improve testing of migrations.


Written by Michael

March 1, 2013 at 6:18 pm

Posted in django, python, testing

Tagged with , ,

8 Responses

Subscribe to comments with RSS.

  1. This looks like a good idea. How do you go about adding data to the database using the old model? There must be some way of getting the corresponding model from the migrations (apps.get_model() is used in data migration code, but this is a parameter passed in). Any thoughts?
    I’m using django 1.7 migrations.


    September 23, 2014 at 11:29 am

    • And I guess this also forces you to write reversible migrations.


      September 23, 2014 at 11:31 am

    • Yes, I should have included an example of creating the data – but you can see the self.start_orm and self.dest_orm above, they were what I used to create the data. It’s still not perfect (there were issues which I can’t recall since I last used it), but it enabled me to create test data, migrate it and test the result (both forwards and backwards).

      I’ve not tried this with django 1.7 migrations yet though – please do let me know if you get it working. Thanks!


      September 23, 2014 at 1:57 pm

  2. See for testing Django migrations.

    Daniel Hahler

    June 22, 2015 at 9:14 pm

    • Nice – yes, that’s similar to what I’m trying to encapsulate in the MigrationTestCase (but it’s been a while since I’ve used that).


      June 23, 2015 at 3:34 am

      • I found the original TestCase of this post a while ago and had wrapped it up into a package. Recently I updated it to work both with South migrations and Django migrations.

        Should work with Django 1.4-1.8

        It’s still very new, but I’d interested if you’d find this useful and if there’s anything I should change/add.

        Andrew Plummer

        August 17, 2015 at 5:24 pm

      • Excellent, thanks Andrew, both for packaging and getting the 1.7+ support working. Can you include my name in the copyright? Otherwise, happy for it to be MIT licensed.


        August 18, 2015 at 12:38 am

    • Nice =), I just commented on the gist a unittest version

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: