70👍
Django 1.4 has a expected behavior when you create the request with RequestFactory that can trigger this error.
To resolve this issue, create your request with RequestFactory and do this:
from django.contrib.messages.storage.fallback import FallbackStorage
setattr(request, 'session', 'session')
messages = FallbackStorage(request)
setattr(request, '_messages', messages)
Works for me!
4👍
A way to solve this quite elegant is to mock the messages module using mock
Say you have a class based view named FooView
in app named 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/')
...
You now can test it with
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]-Different initial data for each form in a Django formset
- [Django]-Django Migrations Add Field with Default as Function of Model
- [Django]-Django equivalent of PHP's form value array/associative array
1👍
In my case (django 1.8) this problem occurs in when unit-test calls signal handler for user_logged_in
signal, looks like messages app has not been called, i.e. request._messages
is not yet set. This fails:
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")
the same call to messages.warning
in normal view function (that is called after) works without any issues.
A workaround I based on one of the suggestions from https://code.djangoproject.com/ticket/17971, use fail_silently
argument only in signal handler function, i.e. this solved my problem:
messages.warning(request, "user has logged in",
fail_silently=True )
- [Django]-How to write django test meant to fail?
- [Django]-How to access the local Django webserver from outside world
- [Django]-Django form: what is the best way to modify posted data before validating?
- [Django]-How do I execute raw SQL in a django migration
- [Django]-Django 1.8: Create initial migrations for existing schema
- [Django]-ImportError: cannot import name 'six' from 'django.utils'
0👍
Tests create custom (tests) database. Maybe you have no messages there or something… Maybe you need setUp() fixtures or something?
Need more info to answer properly.
Why not simply do something like ? You sure run tests in debug mode right?
# settings.py
DEBUG = True
from django.conf import settings
# where message is sent:
if not settings.DEBUG:
# send your message ...
- [Django]-Why use Django on Google App Engine?
- [Django]-How can I set two primary key fields for my models in Django?
- [Django]-Do CSRF attacks apply to API's?
0👍
This builds on Tarsis Azevedo’s answer by creating a MessagingRequest
helper class below.
Given say a KittenAdmin
I’d want to get 100% test coverage for:
from django.contrib import admin, messages
class KittenAdmin(admin.ModelAdmin):
def warm_fuzzy_method(self, request):
messages.warning(request, 'Can I haz cheezburger?')
I created a MessagingRequest
helper class to use in say a test_helpers.py
file:
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()]
Then in a standard 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)
Results:
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%
- [Django]-Using Basic HTTP access authentication in Django testing framework
- [Django]-Django substr / substring in templates
- [Django]-What is {% block content %} and {% endblock content %} for in Django?
0👍
This happened to me in the login_callback signal receiver function when called from a unit test, and the way around the problem was:
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
- [Django]-User Authentication in Django Rest Framework + Angular.js web app
- [Django]-How to update() a single model instance retrieved by get() on Django ORM?
- [Django]-Optimal architecture for multitenant application on django
0👍
I found when I had a problem patching messages the solution was to patch the module from within the class under test (obsolete Django version BTW, YMMV). Pseudocode follows.
my_module.py:
from django.contrib import messages
class MyClass:
def help(self):
messages.add_message(self.request, messages.ERROR, "Foobar!")
test_my_module.py:
from unittest import patch, MagicMock
from my_module import MyClass
class TestMyClass(TestCase):
def test_help(self):
with patch("my_module.messages") as mock_messages:
mock_messages.add_message = MagicMock()
MyClass().help() # shouldn't complain about middleware
- [Django]-Django: How to pre-populate FormView with dynamic (non-model) data?
- [Django]-What is related_name used for?
- [Django]-Celery: WorkerLostError: Worker exited prematurely: signal 9 (SIGKILL)
-1👍
If you’re seeing a problem in your Middleware, then you’re not doing “Unit Test”. Unit tests test a unit of functionality. If you interact with other parts of your system, you’re making something called “integration” testing.
You should try to write better tests, and this kind of problems shouldn’t arise. Try 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)
- [Django]-Django's Double Underscore
- [Django]-Custom QuerySet and Manager without breaking DRY?
- [Django]-Exception: You cannot access body after reading from request's data stream