Return home

Test-Driven Development with Django & South

This is going to be a vastly geekier blog post than my last few, so apologies if this isn't on a topic that interests you!

I'd basically given up on attempting test-driven with Django, given the project I'm currently working on uses models with a lot of South migrations. Just building the database and running the migrations could take a minute or so when running manage.py test, and resetting the database to a clean state meant the test suite would take several minutes to run.

I've had an idea in the back of my mind for a while, and today I finally got around to making it work.

When using SQLite, the test runner doesn't bother to actually hit the filesystem, it just does the whole thing in memory, which is a good deal quicker. Previously, I couldn't use SQLite, because South doesn't like it (since SQLite doesn't support ALTER TABLE).

My realisation was that if I turned off South, I could use SQLite, which I did with this rather hackish file called test_settings.py:

from settings import *

INSTALLED_APPS = [app for app in INSTALLED_APPS if app != 'south']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'test_database.db'
    }
}

I can then do a quick run of the test suite using:

manage.py test --settings=test_settings

Obviously, this doesn't run through my South migrations, which I probably should do from time to time (especially when adding new migrations). I can still test those with:

manage.py test

since by default the test runner will hit my normal settings module, which still has South in INSTALLED_APPS, and which hits my MySQL database.

With my test_settings, I get the following output:

Ran 121 tests in 3.218s

With my default settings, I get:

Ran 121 tests in 326.742s

If I run tests for a particular app (which is generally all I need to do), that difference is 0.312s to 31.064s.

That makes my test run approximately 99% quicker, and well within what I consider an acceptable time to run every time I make small changes to my code.