在不使用Django本身的情况下测试自定义Django中间件

时间:2017-03-23 17:55:43

标签: python django testing django-middleware django-1.10

我在1.10 style中编写了自定义Django中间件,类似于:

class MyMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response
        # some initialization stuff here

    def __call__(self, request):
        # Code executed before view functions are called. 
        # Purpose of this middeware is to add new attribute to request

        # In brief:
        request.new_attribute = some_function_returning_some_object()
        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

请注意,这个中间件被威胁为一个单独的Python模块,不属于我项目中的任何特定应用程序,而是通过pip生活在外部并像其他任何软件包一样安装。它本身不起作用,但只有安装在Django应用程序中。

它工作正常,但是,我想测试一下。到目前为止我所做的是my_tests.py

from my_middleware_module import MyMiddleware
# some @patches
def test_mymiddleware():
    request = Mock()
    assert hasattr(request, 'new_attribute') is False # passes obviously
    # CALL MIDDLEWARE ON REQUEST HERE
    assert hasattr(request, 'new_attribute') is True # I want it to pass

我不知道如何调用request变量上的中间件来修改它。我认为如果我使用类似函数的中间件风格会更容易,但如果我坚持使用我所拥有的东西并且我应该编写测试而不修改中间件会怎么样?

2 个答案:

答案 0 :(得分:5)

问题是你没有调用MyMiddleware的构造函数,也没有通过调用__call__对象的实例来调用MyMiddleware魔术方法。

有很多方法可以测试你描述的行为,我可以想到这个:

首先,我稍微修改了你自己的例子:

class MyMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        request.new_attribute = some_function_returning_some_object()
        import ipdb; ipdb.set_trace()
        response = self.get_response(request)
        return response

def some_function_returning_some_object():
    return 'whatever'

接下来,我通过实际创建Middleware对象并调用新创建的对象来创建测试,因为它是一个函数(因此运行__call__

from mock import patch, Mock
from middle import MyMiddleware
import unittest


class TestMiddleware(unittest.TestCase):

    @patch('middle.MyMiddleware')
    def test_init(self, my_middleware_mock):
        my_middleware = MyMiddleware('response')
        assert(my_middleware.get_response) == 'response'

    def test_mymiddleware(self):
        request = Mock()
        my_middleware = MyMiddleware(Mock())
        # CALL MIDDLEWARE ON REQUEST HERE
        my_middleware(request)
        assert request.new_attribute == 'whatever'

这里有一些有用的链接:

答案 1 :(得分:0)

好的,这有点晚了,但是我遇到了类似的问题,想为Google员工提供答案。

首先,我想出的一些答案建议在测试中创建一个brand实例并设置一个_id,但是this section显然会产生一个{{1}带有HttpRequest的实例不能像HTTP服务器那样工作,并且继续:

  

它不支持中间件。如果需要视图本身正常运行,则测试本身必须提供会话和身份验证属性。

我已经想测试我的注射 是否在RequestFactory对象中,因此我们必须创建一个。首先,我们创建一个虚拟视图:

HttpRequest

然后,我们需要将其链接到RequestFactory中的URL。

HttpRequest

如果您已经使用pytest-django,则可以轻松获得具有def dummy_view(request, *args, **kwargs): return HttpResponse(b"dummy") 固定装置的urls.py实例,调用此URL并从响应中获取path("/dummy", dummy_view, name="dummy") ,如下所示:

HttpClient

但这有一些缺点:

  • 它产生了一个真正的开发服务器进程,因此使种类的测试变慢。
  • 对于真实的Django项目,创建虚拟视图可能不是可行的解决方案,因为您可能需要使用过多的样板文件(例如client)包装URL。我发现这仅对第三方模块有用。