Почему мои unittests Django не знают, что MessageMiddleware установлен?
Я работаю над проектом Django и пишу для него unittests. Однако в тесте, когда я пытаюсь войти в систему пользователя, я получаю эту ошибку:
MessageFailure: You cannot add messages without installing django.contrib.messages.middleware.MessageMiddleware
вход на фактический сайт работает нормально - и сообщение для входа отображается с помощью MessageMiddleware.
в моих тестах, если я делаю это:
from django.conf import settings
print settings.MIDDLEWARE_CLASSES
затем он выводит это:
('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')
который показывает, что MessageMiddleware установлен, когда тесты бежать.
есть ли очевидный шаг, который я пропустил?
обновление
после предложений ниже, похоже, что это настройки.
и settings/__init__.py
такой:
try:
from settings.development import *
except ImportError:
pass
и settings/defaults.py
содержащий большинство стандартных настроек (включая MIDDLEWARE_CLASSES
). А потом ... --8--> переопределяет некоторые из этих значений по умолчанию такой:
from defaults import *
DEBUG = True
# etc
похоже, что мой сайт dev сам отлично работает, используя параметры разработки. Но хотя тесты, похоже, загружают настройки OK (как по умолчанию, так и при разработке)settings.DEBUG
установлено значение False
. Не знаю почему, и не знаю, в этом ли причина проблемы.
8 ответов
Джанго 1.4 ошибка при создании запроса с RequestFactory.
чтобы решить эту проблему, создайте запрос с RequestFactory и этого:
from django.contrib.messages.storage.fallback import FallbackStorage
setattr(request, 'session', 'session')
messages = FallbackStorage(request)
setattr(request, '_messages', messages)
работает для меня!
способ решить эту довольно элегантную проблему-издеваться над модулем сообщений с помощью mock
скажем, у вас есть представление на основе класса с именем FooView
в приложении с именем 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/')
...
теперь вы можете проверить его с
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)
в моем случае (django 1.8) эта проблема возникает, когда модульный тест вызывает обработчик сигнала для user_logged_in
сигнал, похоже, приложение messages не было вызвано, т. е. request._messages
еще не установлен. Это не удается:
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")
тот же вызов messages.warning
в нормальный вид функции (которая вызывается после) работает без каких-либо проблем.
обходной путь я на основе одного из предложений от https://code.djangoproject.com/ticket/17971, используйте fail_silently
аргумент только в сигнале функция обработчика, т. е. это решило мою проблему:
messages.warning(request, "user has logged in",
fail_silently=True )
тесты создайте пользовательскую (тестовую) базу данных. Может, у тебя там нет сообщений... Может быть, вам нужны светильники setUp () или что-то еще?
нужна дополнительная информация, чтобы ответить правильно.
почему бы просто не сделать что-то подобное ? Вы уверены, что запускаете тесты в режиме отладки?
# settings.py
DEBUG = True
from django.conf import settings
# where message is sent:
if not settings.DEBUG:
# send your message ...
это основывается на ответ Тарсиса Азеведо создать MessagingRequest
вспомогательный класс ниже.
дали сказать KittenAdmin
Я хотел бы получить 100% тестовое покрытие для:
from django.contrib import admin, messages
class KittenAdmin(admin.ModelAdmin):
def warm_fuzzy_method(self, request):
messages.warning(request, 'Can I haz cheezburger?')
Я создал MessagingRequest
вспомогательный класс для использования в say a :
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()]
тогда в стандартном 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)
результаты:
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%
Это произошло со мной в функции приемника сигнала login_callback при вызове из модульного теста, и путь вокруг проблемы был:
from django.contrib.messages.storage import default_storage
@receiver(user_logged_in)
def login_callback(sender, user, request, **kwargs):
if not hasattr(request, '_messages'): # fails for tests
request._messages = default_storage(request)
Django 2.0.x
Если вы видите проблему в своем промежуточном ПО, то вы не делаете "модульный тест". Модульные тесты тестируют единицу функциональности. Если вы взаимодействуете с другими частями вашей системы, вы делаете что-то под названием "интеграционное" тестирование.
вы должны попытаться написать лучшие тесты, и такого рода проблемы не должны возникать. Попробуй!--4-->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)