如何正确地对 Django 中间件进行单元测试

How to properly unit test a Django middleware

我必须为多个 Django 中间件(Django > 1.10 风格的中间件)编写单元测试。

项目是一个 API,使用 Django==2.2.3 和 djangorestframework==3.9.4 完成,我正在使用标准的 Django 单元测试模块,以及 APIRequestFactory() 和API来自 Django REST 框架的 Client() 测试函数为我的测试创建模拟请求。

这是我要测试的一个中间件的示例:

from . import models

class BrowserId():

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if hasattr(request, 'COOKIES') and 'mydomain.bid' in request.COOKIES:
            bid = request.COOKIES.get('mydomain.bid', None)
        else:
            bid = None

        request.bid = models.BrowserId(bid) if bid else models.BrowserId.random()

        response = self.get_response(request)

        response.set_cookie(
            conf.BID_COOKIE_KEY,
            value=request.bid,
            max_age=conf.COOKIE_MAX_AGE,
            domain=conf.BID_COOKIE_DOMAIN
        )

        return response

我要测试:

因此,更准确地说,部分测试必须大致如下所示:

from rest_framework.test import APIRequestFactory, APIClient, APITestCase
from my_api.auth import middlewares, models

class MiddlewaresTestCase(APITestCase):

    def test_fresh_browser_id_request(self):
        ??? SOME CODE TO PROCESS THE REQUEST BY THE MIDDLEWARE 
        assert hasattr(request, 'bid')
        assert len(request.bid) == 30

    def test_existing_browser_id_request(self):
        req = APIRequestFactory().get('/')
        mock_bid: str = 'abcd1234'
        req.COOKIES = {cookie_key: mock_bid}
        ??? SOME CODE TO PROCESS THE REQUEST BY THE MIDDLEWARE
        assert hasattr(req, 'bid')
        assert req.bid == mock_bid

    def test_browser_id_response(self):
        mock_bid: str = 'abc123'
        ??? SOME CODE TO PROCESS THE REQUEST BY THE MIDDLEWARE
        ??? SOME CODE TO PROCESS THE REPONSE BY THE MIDDLEWARE
        response = APIClient().get('/')
        assert res.cookies.get(cookie_key) is not None
        assert res.cookies.get(cookie_key).value == mock_bid

等等

但是,如您所见,我不知道具体如何单独执行此操作。更准确地说:

您在 test_browser_id_response 中使用的 APIClient 通过整个堆栈发出模拟请求,因此非常适合测试中间件。我会始终如一地使用它而不是 APIFactory。然后您可以断言 the request attribute of the response。 (请注意,APITestCase 已经为您实例化了一个客户端,您无需创建新客户端。)

def test_existing_browser_id_request(self):
    mock_bid: str = 'abcd1234'
    self.client.cookies[cookie_key] = mock_bid
    response = self.client.get('/')
    req = response.request
    self.assertTrue(hasattr(req, 'bid'))
    self.assertEqual(req.bid, mock_bid)