Persisting Django’s Test Database

After running Django unittests, it may sometimes be useful to manually inspect the test database after unittests are complete. I was working on a complicated network model, trying to resolve an elusive bug in a unittest, and in this specific instance, I thought running a manually written SQL query would be a bit more helpful than dealing with Django’s ORM. Since most people don’t really care about the test database, Django’s unittest framework is understandably hard-coded to destroy it after the tests have ran. Although there’s no simply flag to disable this, after digging around in the code, I found it’s relatively easy enough to change with a couple class method overrides.

First, for convenience, I define a PERSIST_TEST_DATABASE = 1 flag in my settings.py.

Then, my tests.py takes the general form:

from django.conf import settings
from django.test import TestCase
 
if settings.PERSIST_TEST_DATABASE:
    # Disable destruction of the test database.
    from django.db import transaction, connection, connections, DEFAULT_DB_ALIAS
    from django.test.testcases import restore_transaction_methods, connections_support_transactions
    connection.creation.destroy_test_db = lambda *args, **kwargs: None
 
class Test(TestCase):
 
    def _fixture_teardown(self):
        if not settings.PERSIST_TEST_DATABASE or not connections_support_transactions():
            return super(TestCase, self)._fixture_teardown()
 
        # If the test case has a multi_db=True flag, teardown all databases.
        # Otherwise, just teardown default.
        if getattr(self, 'multi_db', False):
            databases = connections
        else:
            databases = [DEFAULT_DB_ALIAS]
 
        restore_transaction_methods()
        for db in databases:
            transaction.commit(using=db)
            transaction.leave_transaction_management(using=db)

My two overrides are connection.creation.destroy_test_db, which I completely disable, and TestCase._fixture_teardown, which is essentially the same as the original, but tweaked to commit instead of rollback the transaction.

Leave a Reply