web-dev-qa-db-ja.com

私のDjango unittestsがMessageMiddlewareがインストールされていることを知らないのはなぜですか?

Djangoプロジェクトに取り組んでいて、そのユニットテストを作成しています。ただし、テストでユーザーをログインしようとすると、次のエラーが発生します。

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を含む)が含まれています。そして、settings.development.pyは、次のようなデフォルトのいくつかをオーバーライドします。

from defaults import *

DEBUG = True
# etc

開発設定を使用すると、開発サイト自体は正常に機能しているようです。ただし、テストでは設定はOK(デフォルトと開発の両方)でロードされているように見えますが、settings.DEBUGFalseに設定されています。理由はわかりませんが、それが問題の原因かどうかはわかりません。

38
Phil Gyford

Django 1.4 バグがあります RequestFactoryでリクエストを作成する場合。

この問題を解決するには、RequestFactoryを使用してリクエストを作成し、次のようにします。

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

私のために働く!

62
Tarsis Azevedo

これを非常にエレガントに解決する方法は、 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)
4
Stephan Hoyer

私の場合(Django 1.8)、この問題は、ユニットテストがuser_logged_inシグナルのシグナルハンドラーを呼び出すときに発生します。メッセージアプリが呼び出されていないように見えます。つまり、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 からの提案の1つに基づく回避策、シグナルハンドラー関数でのみfail_silently引数を使用します。つまり、これで問題が解決しました。

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

これは、単体テストから呼び出されたときに、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

0
mehmet

Settings.pyは1つだけですか?

0
fabiocerqueira

メッセージのパッチ適用で問題が発生したときの解決策は、テスト対象のクラス内からモジュールにパッチを適用することでした(廃止されたDjangoバージョンBTW、YMMV)。擬似コードは次のとおりです。

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
0
Ben Weiner

これは、以下にMessagingRequestヘルパークラスを作成することにより、 Tarsis Azevedoの回答 に基づいています。

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ヘルパークラスを作成して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()]

次に、標準で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%   
0
pzrq

テストはカスタム(テスト)データベースを作成します。たぶん、そこにメッセージなどがないのかもしれません...たぶん、setUp()フィクスチャか何かが必要ですか?

正しく答えるにはもっと情報が必要です。

単純に次のようなことをしてみませんか?確かにデバッグモードでテストを実行しますか?

# settings.py
DEBUG = True

from Django.conf import settings
# where message is sent:
if not settings.DEBUG:
    # send your message ... 
0
garmoncheg