IT

Django에서 다른 설정으로 단위 테스트하는 방법은 무엇입니까?

lottoking 2020. 8. 14. 08:01
반응형

Django에서 다른 설정으로 단위 테스트하는 방법은 무엇입니까?


단위 테스트를 위해 Django 재정의하는 간단한 구현을 실행합니까? 특정 수의 최신 개체를 반환하는 내 모델 중 하나에 관리자가 있습니다. 반환되는 개체 수는 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()기본 제공되는 데 사용됩니다.


편집 :이 대답약간특정 테스트에 대한 설정을 변경하려는 경우 적용 됩니다.

Django 1.4부터 테스트 중에 설정을 재정의하는 방법이 있습니다. https://docs.djangoproject.com/en/dev/topics/testing/tools/#overriding-settings

TestCase는 self.settings 많은 관리자가 대규모 테스트 메서드 또는 전체 TestCase 하위 클래스에 적용 할 수있는 @override_settings 데코레이터도 있습니다.

Django 1.3에 아직 존재하지 않습니다.

모든 테스트에 대한 설정을 변경하고 기본 설정 파일에서 설정을로드하고 재정의 할 수있는 별도의 테스트 설정 파일을 전달합니다. 다른 답변에는 이에 대한 몇 가지 좋은 접근 방식이 있습니다. 나는 hspanderdmitrii의 접근 방식 모두에서 성공적인 변형을 보았습니다 .


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 값을 수정하는 다른 항목이 궁금합니다. 그 "다른 것"이 당신의 테스트 루틴에 의해 촉발 딱, 나는 어떤 양의 원숭이 패치가 테스트 자체의 진실성을 무효화하지 않고 테스트를 확신하지 못합니다.


업데이트 : 아래 솔루션은 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()

--settings테스트를 선택할 때 옵션 을 선택할 수 있습니다.

python manage.py test --settings=mysite.settings_local

구성을 구성을 재정의하는 것이 도움이 될 수 있습니다 제 생각에 테스트를 위해 별도의 파일을 재정합니다. 이렇게하면 테스트를위한 많은 구성이 저장되고, 이는 복구 할 수없는 작업 (예 : 스테이징 데이터베이스 정리)을 수행하지 않습니다.

테스트 파일이 '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에 추가 할 수 있습니다.


@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 

일부 doctest를 수정하는 동안이 문제를 발견했습니다 ... 완전성을 위해 doctest를 사용할 때 설정을 수정하려면 다른 항목을 가져 오기 전에 수정해야합니다.

>>> from django.conf import settings

>>> settings.SOME_SETTING = 20

>>> # Your other imports
>>> from django.core.paginator import Paginator
>>> # etc

pytest를 사용하고 있습니다.

나는 이것을 다음과 같은 방법으로 해결했습니다.

import django    
import app.setting
import modules.that.use.setting

# do some stuff with default setting
setting.VALUE = "some value"
django.setup()
import importlib
importlib.reload(app.settings)
importlib.reload(modules.that.use.setting)
# do some stuff with settings new value

다음과 같이 테스트의 설정을 재정의 할 수 있습니다.

from django.test import TestCase, override_settings

test_settings = override_settings(
    DEFAULT_FILE_STORAGE='django.core.files.storage.FileSystemStorage',
    PASSWORD_HASHERS=(
        'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
    )
)


@test_settings
class SomeTestCase(TestCase):
    """Your test cases in this class"""

다른 파일에서 이러한 동일한 설정이 필요한 경우 test_settings.


하위 디렉토리 (python 패키지)에 여러 테스트 파일이있는 경우 sys.argv에 'test'문자열이 있는지 조건에 따라 이러한 모든 파일에 대한 설정을 재정의 할 수 있습니다.

app
  tests
    __init__.py
    test_forms.py
    test_models.py

__init__.py :

import sys
from project import settings

if 'test' in sys.argv:
    NEW_SETTINGS = {
        'setting_name': value,
        'another_setting_name': another_value
    }
    settings.__dict__.update(NEW_SETTINGS)

최선의 방법은 아닙니다. Celery 브로커를 Redis에서 Memory로 변경하는 데 사용했습니다.

참고 URL : https://stackoverflow.com/questions/913549/how-to-unit-test-with-different-settings-in-django

반응형