如何在Django RequestFactory中设置消息和会话中间件以进行单元测试

17 投票
3 回答
3014 浏览
提问于 2025-04-18 07:34

我有一个需要测试的函数,它需要一个请求作为参数。这个函数没有通过网址暴露出来,所以我不能用测试客户端来测试它。

我需要把一个请求对象传给它,而且这个请求对象需要启用消息中间件,因为这个函数里用到了消息中间件。

我正在使用RequestFactory来创建我的请求。文档上说:

它不支持中间件。如果视图正常工作需要会话和认证属性,必须由测试本身提供。

我该如何用RequestFactory设置消息中间件呢?我想我还需要会话中间件才能让消息中间件正常工作。

这是我当前使用普通RequestFactory时测试产生的错误。

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

这是我正在测试的函数,以便更好地理解这个问题:

from django.contrib import messages as django_messages

def store_to_request(self, request):
        """
        Place all the messages stored in this class into message storage in
        the request object supplied.
        :param request: The request object to which we should store all the messages
        :return: Does not return anything
        """
        for message in self._messages:
            django_messages.add_message(request, message.level, message.message, message.extra_tags,
                                    message.fail_silently)

3 个回答

2

一种与Danag的回答效果相同的方法是,在将请求对象传递给视图或函数之前,先通过会话和消息中间件的process_request方法(按这个顺序)处理请求对象:

from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.messages.middleware import MessageMiddleware

request = request_factory.get()
sm = SessionMiddleware()
sm.process_request(request)
mm = MessageMiddleware()
mm.process_request(request)

为了方便,你可以把上面的操作放在一个方法里:

class MessageDependentTests(TestCase):
    
    def setUp(self):
        self.rf = RequestFactory()
        self.sm = SessionMiddleware()
        self.mm = MessageMiddleware()
        return super().setUp()
        
    def prepare_request(self, request):
        self.sm.process_request(request)
        self.mm.process_request(request)

    def test_something(self):
        request = self.rf.get('/')
        self.prepare_request(request)
        response = my_view(request)
        # test response below
4

如果你不需要测试请求对象本身的行为,可以使用mock库来模拟请求,而不是使用RequestFactory。例如:

import mock

request = mock.MagicMock()

# Call your function using the mocked request
store_to_request(request)
22

这个问题在这里提到过 (点击查看),根据里面的说法,你可以用下面的代码来修复你的单元测试:

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

撰写回答