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

Testing custom Django middleware without using Django itself

我已经用1.10样式对我的自定义django中间件进行了编码,类似于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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中所做的是这样的:

1
2
3
4
5
6
7
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变量上的中间件来修改它。我认为如果我使用类似中间件风格的功能会容易得多,但是如果我坚持使用我拥有的东西,并且我应该只编写测试,而不修改中间件呢?


问题是,您既不调用EDOCX1的构造函数(0),也不通过调用MyMiddleware对象的实例来调用__call__magic方法。

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

首先,我稍微修改了您的示例,使其独立:

1
2
3
4
5
6
7
8
9
10
11
12
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'

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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'

这里有一些有用的链接:

  • 在另一个问题中,你的呼叫和初始呼叫之间的区别是:初始呼叫还是初始呼叫?

  • 从python文档修补的位置:https://docs.python.org/3/library/unittest.mock.html修补的位置

  • pytest文档:http://docs.pytest.org/en/latest/contents.html

  • IPDB简介,用于调试:https://www.safaribooksonline.com/blog/2014/11/18/intro-python-debugger/