Django テストの高速化

Djangoのテストフレームワークは便利なんだけど、テスト実行時に毎回行われるDBテーブルの生成・削除プロセスやFixtureデータのインポート処理に決行時間が掛かってて、ストレスの種になっていた。

テスト中にコンソールを眺めていて特に遅いと感じられるのがcreate table文の実行。モデルの数だけこれが実行されるので、アプリケーションの規模が大きくなるにつれテスト時間も増加してしまう。
DBアクセスが高速化されればいいんだけど、今回使用しているDBのPostgreSQLにはメモリテーブルみたいな仕組みがないため、どうしてもディスクアクセスが発生してしまう。が、ローカル環境では開発用途にしか使ってないのでRAMディスク上にテーブルスペースを作って、そこにテスト用のDBが生成されるようにすればDBアクセスが高速化されるはず。と思い立って、次のようにこれを実現してみた。

まず導入したのが前々から欲しいと思ってたソフト、RamPhantom。手元のデスクトップマシンはWindows XP 32bit版で4GBのメモリを積んでいるので、OSに認識されないメモリが700MB近くあった。IOデータのメモリを持っていなかったので有償版を購入。OS管理外メモリをすべてRAMディスクに割り当てた。ログオフ時にはHDDにRAMディスクをバックアップするように設定。

次に、PostgreSQLのテーブルスペースを「ram」という名前でRAMディスク上に作成。このテーブルスペースにDjangoアプリケーションで使用するデータベースを作成。
これでsyncdb時のテーブル生成も「超」が付くほど高速化された。が、テスト実行時にはPostgreSQLのデフォルトのテーブルスペースにテスト用データベースが作成されてしまっていた。意味ないじゃん。

Djangoには元々DEFAULT_TABLESPACEという設定項目があるけど、Oracleでしか使われてない様子。
というわけで、Djangoのソースに手を加えて、これをPostgreSQLでも使えるようにします。対象ファイルは、django/db/backends/postgresql/creation.py 。sql_table_creation_suffixメソッドを以下のように修正。

def sql_table_creation_suffix(self):
    assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."
    suffix = ''
    if settings.TEST_DATABASE_CHARSET:
        suffix += "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET
    if settings.DEFAULT_TABLESPACE:
        if suffix:
            suffix += ' '
        suffix += "TABLESPACE %s" % settings.DEFAULT_TABLESPACE
    return suffix

TEST_TABLESPACEといった名前で別の設定項目にするのもアリだと思う。この辺りは今後もう少し考えてみる。

そして、settings.pyに DEFAULT_TABLESPACE='ram' を追加して、テスト実行。ちゃんとRAMディスク上のテーブルスペースにテスト用データベースが作成されるようになりました。そして、超速です。テーブル生成のプロセスはもちろん、テストメソッドの実行も速くなってます。
これでテスト実行のストレスが激減しました。

Last updated on July 7, 2015