如何正确地对 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
我要测试:
该浏览器 ID 已成功添加到请求中
该 cookie 已成功设置为响应
因此,更准确地说,部分测试必须大致如下所示:
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
等等
但是,如您所见,我不知道具体如何单独执行此操作。更准确地说:
我不知道在初始化中间件时作为get_response
函数传递什么。我知道它应该是处理视图函数,或者下一个中间件,但我不知道如何通过它,无论如何我想测试它,不管其他的;
我不知道如何只测试处理过的请求而不测试返回的响应。
您在 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)
我必须为多个 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
我要测试:
该浏览器 ID 已成功添加到请求中
该 cookie 已成功设置为响应
因此,更准确地说,部分测试必须大致如下所示:
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
等等
但是,如您所见,我不知道具体如何单独执行此操作。更准确地说:
我不知道在初始化中间件时作为
get_response
函数传递什么。我知道它应该是处理视图函数,或者下一个中间件,但我不知道如何通过它,无论如何我想测试它,不管其他的;我不知道如何只测试处理过的请求而不测试返回的响应。
您在 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)