I have to write unit tests for several Django Middlewares (Django > 1.10 styled middlewares).
Project is an API, done with Django==2.2.3 and djangorestframework==3.9.4, I'm using standard Django unit testing module, and APIRequestFactory() and APIClient() test functions from Django REST framework to create mock requests for my tests.
Here is an example of one middleware I want to test:
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
I want to test:
That browser ID has successfully been added to the request
That cookie has successfully been set on the response
So, to be more precise, part of the tests would vaguely have to look like this:
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
etc.
But, as one can see, I don't know exactly how to individually do that. More precisely:
I don't know what to pass as a get_response
function when initializing the middleware. I know it is supposed to be the processing view function, or the next middleware, but I don't know how to pass that and anyway I want to test it regardless of the rest;
I don't know how to test only the processed request and not the returned response.
The APIClient, which you use in test_browser_id_response
, makes a simulated request through the whole stack and is therefore ideal in testing middleware. I would use that consistently rather than the APIFactory. You can then assert on the request
attribute of the response. (Note, APITestCase already instantiates a client for you, you don't need to create a new one.)
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)