web-dev-qa-db-ja.com

Djangoテストデータベースをメモリ内でのみ実行する方法は?

My Django単体テストの実行には時間がかかるので、それを高速化する方法を探しています。 [〜#〜] ssd [〜 #〜] 、しかし、それにも欠点があることは知っています。もちろん、コードでできることはありますが、構造的な修正を探しています。毎回再構築/南に移行するため、ここに私のアイデアがあります...

テストデータベースは常に非常に小さいことがわかっているので、テストデータベース全体を常にRAMに保持するようにシステムを構成できないのはなぜですか?ディスクには絶対に触れないでください。 Djangoでこれを設定するにはどうすればよいですか? MySQL を使用し続けたいと思いますが、これは本番環境で使用しているものですが、 SQLite 3または他の何かがこれを簡単にするなら、私はそのようにします。

SQLiteまたはMySQLには、完全にメモリ内で実行するオプションがありますか? RAMディスクを構成してから、テストデータベースを構成してそのデータをそこに格納することは可能ですが、Django/MySQLは特定のデータベースに別のデータディレクトリを使用します。特に、実行ごとに消去され、再作成されるためです(Mac FWIWを使用しています)。

116
Leopd

テストの実行時にデータベースエンジンをsqlite3に設定すると、 Djangoはメモリ内データベースを使用します

私のsettings.pyで次のようなコードを使用して、テストの実行時にエンジンをsqliteに設定しています。

if 'test' in sys.argv:
    DATABASE_ENGINE = 'sqlite3'

またはDjango 1.2:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'sqlite3'}

そして最後にDjango 1.3および1.4:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'Django.db.backends.sqlite3'}

(Django 1.3の場合、バックエンドへの完全なパスは必ずしも必要ではありませんが、設定は前方互換性があります。)

Southの移行に問題がある場合は、次の行を追加することもできます。

    SOUTH_TESTS_MIGRATE = False
155
Etienne

私は通常、テスト用に個別の設定ファイルを作成し、テストコマンドで使用します。

python manage.py test --settings=mysite.test_settings myapp

2つの利点があります。

  1. Sys.argvでtestまたはそのようなマジックワードを確認する必要はありません、test_settings.pyは単に

    from settings import *
    
    # make tests faster
    SOUTH_TESTS_MIGRATE = False
    DATABASES['default'] = {'ENGINE': 'Django.db.backends.sqlite3'}
    

    または、ニーズに合わせてさらに微調整して、テスト設定と運用設定を明確に分離することもできます。

  2. 別の利点は、微妙なバグを回避するために、sqlite3の代わりに本番データベースエンジンでテストを実行できることです。

    python manage.py test --settings=mysite.test_settings myapp
    

    コードをコミットする前に1回実行する

    python manage.py test myapp
    

    すべてのテストが本当に合格していることを確認するだけです。

80
Anurag Uniyal

MySQLは、「MEMORY」というストレージエンジンをサポートしています。これは、データベース構成で構成できます(settings.py) など:

    'USER': 'root',                      # Not used with sqlite3.
    'PASSWORD': '',                  # Not used with sqlite3.
    'OPTIONS': {
        "init_command": "SET storage_engine=MEMORY",
    }

MEMORYストレージエンジンはblob/text列をサポートしていないことに注意してください。したがって、Django.db.models.TextFieldこれはあなたには機能しません。

22
muudscope

主な質問に答えることはできませんが、速度を上げるためにできることがいくつかあります。

まず、MySQLデータベースがInnoDBを使用するように設定されていることを確認してください。その後、トランザクションを使用して各テストの前にdbの状態をロールバックできますが、これは私の経験では大幅な高速化につながりました。 settings.pyでデータベース初期化コマンドを渡すことができます(Django 1.2構文):

DATABASES = {
    'default': {
            'ENGINE':'Django.db.backends.mysql',
            'Host':'localhost',
            'NAME':'mydb',
            'USER':'whoever',
            'PASSWORD':'whatever',
            'OPTIONS':{"init_command": "SET storage_engine=INNODB" } 
        }
    }

第二に、毎回南の移行を実行する必要はありません。 settings.pyでSOUTH_TESTS_MIGRATE = Falseを設定すると、データベースは単純なsyncdbで作成されます。これは、すべての歴史的な移行を実行するよりもはるかに高速です。

15
Daniel Roseman

あなたは二重調整を行うことができます:

  • トランザクションテーブルを使用します。初期フィクスチャの状態は、TestCaseのたびにデータベースロールバックを使用して設定されます。
  • データベースデータディレクトリをramdiskに配置します。データベースの作成に関する限り、テストの実行も高速になります。

私は両方のトリックを使用していますが、とてもうれしいです。

UbuntuでMySQL用に設定する方法:

$ Sudo service mysql stop
$ Sudo cp -pRL /var/lib/mysql /dev/shm/mysql

$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ Sudo service mysql start

データベースをメモリから再起動すると失われるため、テスト用です。

10
Potr Czachur

別のアプローチ:RAM Disk。を使用するtempfsでMySQLの別のインスタンスを実行します。このブログ投稿の手順: Django でテストしています。

利点:

  • 実稼働サーバーが使用するデータベースとまったく同じデータベースを使用します
  • デフォルトのmysql構成を変更する必要はありません
3
neves

Anuragの答えを拡張して、同じtest_settingsを作成し、manage.pyに以下を追加することでプロセスを簡素化しました

if len(sys.argv) > 1 and sys.argv[1] == "test":
    os.environ.setdefault("Django_SETTINGS_MODULE", "mysite.test_settings")
else:
    os.environ.setdefault("Django_SETTINGS_MODULE", "mysite.settings")

sysはすでにインポートされており、manage.pyはコマンドライン経由でのみ使用されるため、設定を乱雑にする必要がないため、よりクリーンに見えます

2
Alvin