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

Pho*_*ght 5 python testing django django-middleware django-1.10

我已经用1.10样式编写了自定义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
Run Code Online (Sandbox Code Playgroud)

请注意,该中间件正受到威胁,因为它是一个单独的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
Run Code Online (Sandbox Code Playgroud)

我不知道如何在request变量上调用中间件以对其进行修改。我认为如果使用类似函数的中间件样式会容易得多,但是如果坚持使用现有的东西又应该只编写测试而不修改中间件怎么办?

Enr*_*aez 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'
Run Code Online (Sandbox Code Playgroud)

接下来,我通过实际创建中间件对象并调用新创建的对象作为函数来创建测试(因此__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'
Run Code Online (Sandbox Code Playgroud)

这里有一些有用的链接: