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.