2011-02-02 23 views
3

私は次の問題に直面しています。この例では単体テストでDjango FileSystemStorageの設定をうまく置き換える(パッチする)にはどうすればいいですか?

class Package(models.Model): 
    name = models.CharField(max_length=64) 
    file = models.FileField(upload_to="subdir", 
          storage=settings.PACKAGE_STORAGE, 
          null=True) 

エッセンシャルはFileFieldコンストラクタの引数storage=です:私はややこのようになりますモデルを持っています。それはsettings.pyの値で満たされます。そこには、次のコードがあります:

from django.core.files.storage import FileSystemStorage 
PACKAGE_STORAGE = FileSystemStorage(location="/var/data", base_url="/") 

生産上の使用のために、これはうまくいきます。しかし私の単体テストでは、私が行ったアップロードは生産データを含む/var/dataに書かれています。私は

from django.conf import settings  # This is line 1 
from tempfile import mkdtemp 
settings.PACKAGE_STORAGE = FileSystemStorage(location=mkdtemp(), base_url="/") 

# rest of the imports and testing code below 

このよう packages/tests.pyPACKAGE_STOREをスワップアウトしようとしましたが、本当の問題は、したがって、テストファイルがロードされる 前に、 packagesアプリとそのモデルがすでにロードされているということです、そして、 PACKAGE_STORAGE設定テストセットアップコードで変更する前に解決されました。

テストコンテキストでこの特定の設定を上書きする優雅な方法はありますか?

+0

補足:私は 'location'と' storage'引数について怠惰な評価を試みましたが、役に立たなかった: 'FileSystemStorage'は' .startswith() '' FileField'は '' .get_valid_name() 'を呼び出すことによって、遅延した' storage = '引数をただちに評価します。 – nvie

+0

'PACKAGE_STORAGE'とは何ですか? – Flimm

答えて

3

あなたはジャンゴを通じてテストを実行する場合、これは後のコースの

if 'test' in sys.argv: 
    settings.DEFAULT_FILE_STORAGE = FileSystemStorage(location=mkdtemp(), base_url="/") 

を動作するはずです;)これはエレガントカウントした場合

DEFAULT_FILE_STORAGE = FileSystemStorage(location="/var/data", base_url="/") 
+0

私は 'argv'値のテストはかなり醜いと思いますが、これは少なくとも代替設定ファイルを覚えておく必要はありません。 – nvie

+0

@Flimm私はDEFAULT_FILE_STORAGEを意味しました –

7

が分からないのですが、あなたは異なる設定を使用することができます

# test_settings.py 

from settings import * 

PACKAGE_STORAGE = FileSystemStorage(location='/test/files', base_url="/") 
:のようなテストのためにファイル...

何か

次に、テスト設定、python manage.py test --settings=test_settingsを使用してテストを実行します。

+0

あなたは自分自身を冗談しています@meshantz !?これは、それが得るほどエレガントです。唯一の方法ではなく、最もエレガントな方法です。 –

+0

@kRONありがとうございます。私は、異なる設定ファイルを使用すると悪用や不幸なテストワイドな副作用を招く恐れがあります。あなたが上書きするものを慎重にしていない場合。 – meshantz

+0

私はdjango testのための--settings paramについては知らなかった:) –

2

オーバーライド動的モデルのFileFieldのインスタンスのための基本となる記憶域の実装:私はちょうど私のカスタムのテストランナーに追加することでこれを解決し

def setUp(self): 
    self._field = Package._meta.get_field_by_name('file')[0] 
    self._default_storage = self._field.storage 
    test_storage = FileSystemStorage(location=mkdtemp(), 
             base_url="/") 

    self._field.storage = test_storage 

def tearDown(self): 
    self._field = self._default_storage 
2

。カスタムテストランナーを追加する方法については、DjangoのドキュメントのDefining a test runnerを参照してください。私のコードは次のようになります。

import shutil 
import tempfile 
from django.test.simple import DjangoTestSuiteRunner 
from django.conf import settings 

class CustomTestRunner(DjangoTestSuiteRunner): 

    def setup_test_environment(self, **kwargs): 
     super(CustomTestRunner, self).setup_test_environment(**kwargs) 
     self.backup = {} 
     self.backup['DEFAULT_FILE_STORAGE'] = settings.DEFAULT_FILE_STORAGE 
     settings.DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' 
     self.backup['MEDIA_ROOT'] = settings.MEDIA_ROOT 
     self.temp_media_root = tempfile.mkdtemp(prefix="myapp-tests") 
     settings.MEDIA_ROOT = self.temp_media_root 

    def teardown_test_environment(self, **kwargs): 
     super(CustomTestRunner, self).teardown_test_environment(**kwargs) 
     for name, value in self.backup.iteritems(): 
      setattr(settings, name, value) 

    def run_tests(self, test_labels, **kwargs): 
     try: 
      test_results = super(CustomTestRunner, self).run_tests(test_labels, **kwargs) 
     finally: 
      shutil.rmtree(self.temp_media_root, ignore_errors=True) 

これはカスタムテストスイートのいくつかのメソッドをオーバーライドします。 setup_test_environmentは以前の設定をバックアップし、クラス属性に格納します。 teardown_test_environmentは、以前の状態に戻します。 run_testsメソッドはtry/finallyブロックを使用して、例外が発生してもテスト後に一時ディレクトリが削除されるようにします。

関連する問題