136

単体テストの Django 設定をオーバーライドする簡単なメカニズムはありますか? モデルの 1 つに、特定の数の最新オブジェクトを返すマネージャーがいます。返されるオブジェクトの数は、NUM_LATEST 設定によって定義されます。

これにより、誰かが設定を変更した場合、テストが失敗する可能性があります。setUp()の設定をオーバーライドして、後で復元するにはどうすればよいtearDown()ですか? それが不可能な場合、メソッドにモンキー パッチを適用するか、設定をモックする方法はありますか?

編集:これが私のマネージャーコードです:

class LatestManager(models.Manager):
    """
    Returns a specific number of the most recent public Articles as defined by 
    the NEWS_LATEST_MAX setting.
    """
    def get_query_set(self):
        num_latest = getattr(settings, 'NEWS_NUM_LATEST', 10)
        return super(LatestManager, self).get_query_set().filter(is_public=True)[:num_latest]

マネージャーはsettings.NEWS_LATEST_MAXクエリセットをスライスするために使用します。はgetattr()、設定が存在しない場合にデフォルトを提供するために使用されます。

4

13 に答える 13

180

編集:この回答は、少数特定のテストの設定を変更する場合に適用されます。

Django 1.4 以降、テスト中に設定をオーバーライドする方法があります: https://docs.djangoproject.com/en/stable/topics/testing/tools/#overriding-settings

TestCaseself.settingsコンテキスト マネージャがあり、テスト メソッドまたはサブクラス全体に適用できるデコレータもあり@override_settingsますTestCase

これらの機能は、Django 1.3 にはまだ存在しませんでした。

すべてのテストの設定を変更する場合は、メインの設定ファイルから設定を読み込んで上書きできる、テスト用の別の設定ファイルを作成する必要があります。他の回答には、これに対するいくつかの良いアプローチがあります。hspanderdmitrii の両方のアプローチで成功したバリエーションを見てきました。

于 2011-06-20T17:35:09.393 に答える
48

UnitTestインスタンス プロパティの設定や読み取りなど、サブクラスに対して好きなことを行うことができます。

from django.conf import settings

class MyTest(unittest.TestCase):
   def setUp(self):
       self.old_setting = settings.NUM_LATEST
       settings.NUM_LATEST = 5 # value tested against in the TestCase

   def tearDown(self):
       settings.NUM_LATEST = self.old_setting

ただし、django テスト ケースはシングル スレッドで実行されるため、他に NUM_LATEST 値を変更している可能性があるものについて知りたいです。その「何か他のもの」がテストルーチンによってトリガーされた場合、テスト自体の真実性を無効にすることなく、モンキーパッチをいくらでも適用してもテストが保存されるかどうかはわかりません。

于 2009-05-27T01:50:13.557 に答える
28

--settingsテストの実行時にオプションを渡すことができます

python manage.py test --settings=mysite.settings_local
于 2016-06-10T06:32:29.180 に答える
25

実行時の設定構成のオーバーライドが役立つかもしれませんが、私の意見では、テスト用に別のファイルを作成する必要があります。これにより、テスト用の構成が大幅に節約され、元に戻せないこと (ステージング データベースのクリーニングなど) を行うことはなくなります。

テスト ファイルが「my_project/test_settings.py」にあるとします。

settings = 'my_project.test_settings' if 'test' in sys.argv else 'my_project.settings'

あなたのmanage.pyで。これにより、実行時にpython manage.py testtest_settings のみを使用することが保証されます。pytest などの他のテスト クライアントを使用している場合は、これを pytest.ini に簡単に追加できます。

于 2015-06-15T13:44:14.183 に答える
20

更新: 以下のソリューションは、Django 1.3.x 以前でのみ必要です。>1.4 については、slinkp の回答を参照してください。

テストで設定を頻繁に変更し、Python ≥2.5 を使用する場合、これも便利です。

from contextlib import contextmanager

class SettingDoesNotExist:
    pass

@contextmanager
def patch_settings(**kwargs):
    from django.conf import settings
    old_settings = []
    for key, new_value in kwargs.items():
        old_value = getattr(settings, key, SettingDoesNotExist)
        old_settings.append((key, old_value))
        setattr(settings, key, new_value)
    yield
    for key, old_value in old_settings:
        if old_value is SettingDoesNotExist:
            delattr(settings, key)
        else:
            setattr(settings, key, old_value)

次に、次のことができます。

with patch_settings(MY_SETTING='my value', OTHER_SETTING='other value'):
    do_my_tests()
于 2010-08-19T08:28:12.673 に答える
13

@override_settings本番環境とテスト環境の構成に大きな違いがない場合に最適です。

それ以外の場合は、別の設定ファイルを使用することをお勧めします。この場合、プロジェクトは次のようになります。

your_project
    your_app
        ...
    settings
        __init__.py
        base.py
        dev.py
        test.py
        production.py
    manage.py

そのため、ほとんどの設定をbase.py入れてから、他のファイルにすべてをインポートし、いくつかのオプションを上書きする必要があります。test.pyファイルは次のようになります。

from .base import *

DEBUG = False

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'app_db_test'
    }
}

PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.MD5PasswordHasher',
)

LOGGING = {}

次に--settings、@MicroPyramid の回答のようにオプションを指定するか、DJANGO_SETTINGS_MODULE環境変数を指定して、テストを実行する必要があります。

export DJANGO_SETTINGS_MODULE=settings.test
python manage.py test 
于 2016-12-27T17:41:26.257 に答える
3

いくつかのdoctestを修正しようとしているときにこれを見つけました...完全を期すために、doctestを使用するときに設定を変更する場合は、他のものをインポートする前に変更する必要があります...

>>> from django.conf import settings

>>> settings.SOME_SETTING = 20

>>> # Your other imports
>>> from django.core.paginator import Paginator
>>> # etc
于 2009-12-14T15:26:21.987 に答える