I have coded my custom Django middleware in the 1.10 style, similar to this:
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
Note, that this middleware is being threaten as a separate Python module, not belonging to any particular application in my project, but living outside and being installed like any other package, via pip. It does not work itself, but only if installed in Django app.
It works fine, however, I would like to test it. What I've made so far is something like this in 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
I don't know how to call middleware on request
variable to modify it. I think it would be much easier if I used function-like middleware style, but what if I'm stuck with what I have and I am supposed ony to write tests, without modifying middleware?
The problem is that you are not calling neither the constructor of MyMiddleware
neither invoking the __call__
magic method by invoking the instance of a MyMiddleware
object.
There are many ways to test the behaviour that you described, I can think of this one:
First, I slightly modified your example to be self contained:
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()
response = self.get_response(request)
return response
def some_function_returning_some_object():
return 'whatever'
Next, I created the tests by actually creating the Middleware object and invoking the newly created object as it was a function (so __call__
is run)
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'
Here there are some useful links:
Difference between __call__ and __init__ in another SO question: __init__ or __call__?
Where to patch from the python docs: https://docs.python.org/3/library/unittest.mock.html#where-to-patch
pytest docs: http://docs.pytest.org/en/latest/contents.html
ipdb intro, useful for debugging: https://www.safaribooksonline.com/blog/2014/11/18/intro-python-debugger/