template - Cómo probar la unidad con diferentes configuraciones en Django?
templates django python (8)
¿Hay algún mecanismo simple para anular la configuración de Django para una prueba unitaria? Tengo un administrador en uno de mis modelos que devuelve un número específico de los últimos objetos. La cantidad de objetos que devuelve se define mediante una configuración NUM_LATEST.
Esto tiene el potencial de hacer que mis pruebas fallen si alguien cambiara la configuración. ¿Cómo puedo anular las configuraciones en setUp()
y luego restaurarlas en tearDown()
? Si eso no es posible, ¿hay alguna forma de que yo pueda parchear el método o simular la configuración?
EDITAR: Aquí está mi código de administrador:
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]
El administrador usa settings.NEWS_LATEST_MAX
para cortar el conjunto de consulta. El getattr()
se usa simplemente para proporcionar un valor predeterminado si la configuración no existe.
A pesar de que la configuración general de configuración en el tiempo de ejecución puede ayudar, en mi opinión, debe crear un archivo separado para la prueba. Esto ahorra mucha configuración para las pruebas y esto garantizaría que nunca termine haciendo algo irreversible (como limpiar la base de datos de etapas).
Supongamos que su archivo de prueba existe en ''my_project / test_settings.py'', agregue
settings = ''my_project.test_settings'' if ''test'' in sys.argv else ''my_project.settings''
en su manage.py Esto garantizará que cuando ejecute la python manage.py test
manage.py solo use test_settings. Si está utilizando algún otro cliente de prueba como Pytest, podría agregarlo tan fácilmente a pytest.ini
EDITAR: esta respuesta se aplica si desea cambiar la configuración de un pequeño número de pruebas específicas .
Desde Django 1.4, hay formas de anular la configuración durante las pruebas: https://docs.djangoproject.com/en/dev/topics/testing/tools/#overriding-settings
TestCase tendrá un administrador de contexto selfsettings, y también habrá un decorador @override_settings que se puede aplicar a un método de prueba o a toda una subclase de TestCase.
Estas características aún no existían en Django 1.3.
Si desea cambiar la configuración de todas sus pruebas, querrá crear un archivo de configuración separado para la prueba, que puede cargar y anular la configuración de su archivo de configuración principal. Hay varios buenos enfoques para esto en las otras respuestas; He visto variaciones exitosas en los hspander''s dmitrii''s y dmitrii''s .
Encontré esto mientras trataba de arreglar algunos doctests ... Para completar, quiero mencionar que si va a modificar la configuración cuando usa doctests, debe hacerlo antes de importar cualquier otra cosa ...
>>> from django.conf import settings
>>> settings.SOME_SETTING = 20
>>> # Your other imports
>>> from django.core.paginator import Paginator
>>> # etc
Estoy usando Pytest.
Pude resolver esto de la siguiente manera:
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
Puede hacer lo que quiera con la subclase UnitTest
, incluidas las propiedades de configuración y lectura de instancia:
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
Como los casos de prueba de django se ejecutan en un único subproceso, sin embargo, tengo curiosidad acerca de qué más puede estar modificando el valor NUM_LATEST. Si su rutina de prueba desencadena esa "otra cosa", entonces no estoy seguro de que la cantidad de parches de mono guarde la prueba sin invalidar la veracidad de las pruebas.
Puede pasar la opción --settings
cuando ejecuta pruebas
python manage.py test --settings=mysite.settings_local
@override_settings
es excelente si no tiene muchas diferencias entre las configuraciones de entorno de producción y prueba.
En otro caso, será mejor que tengas diferentes archivos de configuración. En este caso, su proyecto se verá así:
your_project
your_app
...
settings
__init__.py
base.py
dev.py
test.py
production.py
manage.py
Por lo tanto, necesita tener la mayoría de sus configuraciones en base.py
y luego en otros archivos, necesita importar todo desde allí y anular algunas opciones. Así es como se test.py
tu archivo 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 = {}
Y luego debes especificar la opción --settings
como en @MicroPyramid answer, o especificar la variable de entorno DJANGO_SETTINGS_MODULE
y luego puedes ejecutar tus pruebas:
export DJANGO_SETTINGS_MODULE=settings.test
python manage.py test
Actualización : la solución a continuación solo es necesaria en Django 1.3.xy versiones anteriores. Para> 1.4 ver la respuesta de slinkp .
Si cambia la configuración con frecuencia en sus pruebas y usa Python ≥2.5, esto también es útil:
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)
Entonces puedes hacer:
with patch_settings(MY_SETTING=''my value'', OTHER_SETTING=''other value''):
do_my_tests()