django unit-testing messages middleware

¿Por qué mis pruebas de unidad Django no saben que MessageMiddleware está instalado?



unit-testing messages (7)

¿Solo tienes un settings.py?

Estoy trabajando en un proyecto de Django y estoy escribiendo pruebas de unidad para él. Sin embargo, en una prueba, cuando intento registrar un usuario, obtengo este error:

MessageFailure: You cannot add messages without installing django.contrib.messages.middleware.MessageMiddleware

Iniciar sesión en el sitio real funciona bien, y se muestra un mensaje de inicio de sesión utilizando el MessageMiddleware.

En mis pruebas, si hago esto:

from django.conf import settings print settings.MIDDLEWARE_CLASSES

Luego produce esto:

(''django.middleware.cache.UpdateCacheMiddleware'', ''django.middleware.common.CommonMiddleware'', ''django.contrib.sessions.middleware.SessionMiddleware'', ''django.middleware.csrf.CsrfViewMiddleware'', ''django.contrib.auth.middleware.AuthenticationMiddleware'', ''django.contrib.messages.middleware.MessageMiddleware'', ''django.middleware.clickjacking.XFrameOptionsMiddleware'', ''django.middleware.cache.FetchFromCacheMiddleware'', ''debug_toolbar.middleware.DebugToolbarMiddleware'')

Lo cual parece mostrar que el MessageMiddleware está instalado cuando se ejecutan las pruebas.

¿Hay un paso obvio que me falta?

ACTUALIZAR

Después de las sugerencias a continuación, parece que es una cosa de configuración.

Actualmente tengo la settings/__init__.py así:

try: from settings.development import * except ImportError: pass

y settings/defaults.py contienen la mayoría de las configuraciones estándar (incluyendo MIDDLEWARE_CLASSES ). Y luego settings.development.py anula algunos de los valores predeterminados como este:

from defaults import * DEBUG = True # etc

Parece que mi sitio de desarrollo funciona bien, usando la configuración de desarrollo. Pero a pesar de que las pruebas parecen cargar la configuración de OK (ambos valores predeterminados y el desarrollo), la settings.DEBUG se establece en False . No sé por qué, o si esa es la causa del problema.


Django 1.4 tiene un error al crear la solicitud con RequestFactory.

Para resolver este problema, cree su solicitud con RequestFactory y haga esto:

from django.contrib.messages.storage.fallback import FallbackStorage setattr(request, ''session'', ''session'') messages = FallbackStorage(request) setattr(request, ''_messages'', messages)

¡Funciona para mi!


En mi caso (django 1.8), este problema se produce cuando la unidad de prueba llama al controlador de señal para la señal user_logged_in , parece que la aplicación de mensajes no se ha llamado, es decir, request._messages todavía no está establecida. Esto falla:

from django.contrib.auth.signals import user_logged_in ... @receiver(user_logged_in) def user_logged_in_handler(sender, user, request, **kwargs): ... messages.warning(request, "user has logged in")

la misma llamada a messages.warning en la función de vista normal (que se llama después) funciona sin problemas.

Una solución alternativa basada en una de las sugerencias de https://code.djangoproject.com/ticket/17971 , use el argumento fail_silently solo en la función del manejador de señal, es decir, esto resolvió mi problema:

messages.warning(request, "user has logged in", fail_silently=True )


Esto se basa en share al crear a continuación una clase auxiliar de MessagingRequest .

Dado que diga KittenAdmin me gustaría obtener una cobertura de prueba del 100% para:

from django.contrib import admin, messages class KittenAdmin(admin.ModelAdmin): def warm_fuzzy_method(self, request): messages.warning(request, ''Can I haz cheezburger?'')

test_helpers.py una clase de ayuda de MessagingRequest para utilizar, por ejemplo, en un archivo test_helpers.py :

from django.contrib.messages.storage.fallback import FallbackStorage from django.http import HttpRequest class MessagingRequest(HttpRequest): session = ''session'' def __init__(self): super(MessagingRequest, self).__init__() self._messages = FallbackStorage(self) def get_messages(self): return getattr(self._messages, ''_queued_messages'') def get_message_strings(self): return [str(m) for m in self.get_messages()]

Luego, en un estándar Django tests.py :

from django.contrib.admin.sites import AdminSite from django.test import TestCase from cats.kitten.admin import KittenAdmin from cats.kitten.models import Kitten from cats.kitten.test_helpers import MessagingRequest class KittenAdminTest(TestCase): def test_kitten_admin_message(self): admin = KittenAdmin(model=Kitten, admin_site=AdminSite()) expect = [''Can I haz cheezburger?''] request = MessagingRequest() admin.warm_fuzzy_method(request) self.assertEqual(request.get_message_strings(), expect)

Resultados:

coverage run --include=''cats/kitten/*'' manage.py test; coverage report -m Creating test database for alias ''default''... . ---------------------------------------------------------------------- Ran 1 test in 0.001s OK Destroying test database for alias ''default''... Name Stmts Miss Cover Missing ---------------------------------------------------------------------- cats/kitten/__init__.py 0 0 100% cats/kitten/admin.py 4 0 100% cats/kitten/migrations/0001_initial.py 5 0 100% cats/kitten/migrations/__init__.py 0 0 100% cats/kitten/models.py 3 0 100% cats/kitten/test_helpers.py 11 0 100% cats/kitten/tests.py 12 0 100% ---------------------------------------------------------------------- TOTAL 35 0 100%


Las pruebas crean una base de datos personalizada (pruebas). Tal vez no tengas mensajes allí o algo ... ¿Tal vez necesites accesorios setUp () o algo así?

Necesita más información para responder correctamente.

¿Por qué no simplemente hacer algo como? ¿Seguro que ejecutas pruebas en modo de depuración, verdad?

# settings.py DEBUG = True from django.conf import settings # where message is sent: if not settings.DEBUG: # send your message ...


Si ve un problema en su Middleware, entonces no está haciendo "Prueba de Unidad". Las pruebas unitarias prueban una unidad de funcionalidad. Si interactúa con otras partes de su sistema, está haciendo algo llamado prueba de "integración".

Deberías intentar escribir mejores pruebas, y este tipo de problemas no deberían surgir. Pruebe RequestFactory . ;)

def test_some_view(self): factory = RequestFactory() user = get_mock_user() request = factory.get("/my/view") request.user = user response = my_view(request) self.asssertEqual(status_code, 200)


Una forma de resolver esto bastante elegante es burlarse del módulo de mensajes utilizando mock

Digamos que tiene una vista basada en clase llamada FooView en la aplicación llamada myapp

from django.contrib import messages from django.views.generic import TemplateView class FooView(TemplateView): def post(self, request, *args, **kwargs): ... messages.add_message(request, messages.SUCCESS, ''/o/ Profit /o/'') ...

Ahora puedes probarlo con

def test_successful_post(self): mock_messages = patch(''myapp.views.FooView.messages'').start() mock_messages.SUCCESS = success = ''super duper'' request = self.rf.post(''/'', {}) view = FooView.as_view() response = view(request) msg = _(u''/o/ Profit /o/'') mock_messages.add_message.assert_called_with(request, success, msg)