Как провести модульный тест с различными настройками в Django?
есть ли простой механизм для переопределения настроек Django для модульного теста? У меня есть менеджер на одной из моих моделей, который возвращает определенное количество последних объектов. Количество объектов, которые он возвращает определяется параметрами NUM_LATEST.
это может привести к сбою моих тестов, если кто-то изменит настройку. Как я могу переопределить настройки на setUp()
и впоследствии восстановить их на tearDown()
? Если это невозможно, есть ли способ я могу обезьяна исправьте метод или издевайтесь над настройками?
EDIT: вот мой код менеджера:
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()
чтобы обеспечить значение по умолчанию, если параметр не существует.
8 ответов:
изменить: этот ответ применяется, если вы хотите изменить настройки для маленький количество конкретные тесты.
начиная с Django 1.4, есть способы переопределить настройки во время тестов: https://docs.djangoproject.com/en/dev/topics/testing/tools/#overriding-settings
TestCase будет иметь себя.контекстный менеджер настроек, а также декоратор @override_settings, который можно применить к методу тестирования или к целому Подкласс TestCase.
эти функции еще не существовали в Django 1.3.
Если вы хотите изменить параметры все ваши тесты, вы хотите создать отдельный файл настроек для теста, который может загружать и переопределять настройки из вашего основного файла настроек. Есть несколько хороших подходов к этому в других ответах; я видел успешные вариации на обоих hspander это и Дмитриевская!--8--> подходы.
Вы можете сделать все, что угодно, чтобы
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 см. ответ слинка.
Если вы часто меняете настройки в своих тестах и используете 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()
хотя переопределение настроек конфигурации во время выполнения может помочь, на мой взгляд, вы должны создать отдельный файл для тестирования. Это экономит много конфигурации для тестирования, и это гарантирует, что вы никогда не будете делать что-то необратимое (например, очистка промежуточной базы данных).
скажем, ваш тестовый файл существует в 'my_project/test_settings.py', добавить
settings = 'my_project.test_settings' if 'test' in sys.argv else 'my_project.settings'
в вашем manage.py. это будет гарантировать, что при запуске
python manage.py test
вы используете только test_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
нашел это при попытке исправить некоторые doctests... Для полноты я хочу упомянуть, что если вы собираетесь изменить настройки при использовании doctests, вы должны сделать это перед импортом чего-либо еще...
>>> 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