I'm learning unittest
and unittest.mock
with the latter not quite clicking.
I'm mocking the response of an end-point and had the following:
import unittest
from unittest.mock import patch
from rest_framework.test import APIClient
class CoreTestCase(unittest.TestCase):
@patch('core.views.CoreViewSet.list')
def test_response(self, mock_get):
mock_get.return_value = [{'hello': 'world'}]
client = APIClient()
response = client.get('/core/')
print(response.data)
Which resulted in the following error:
AssertionError: Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `<class 'list'>`
Made sense because DRF uses Response
.
To get around the error I modified to:
import unittest
from unittest.mock import patch
from rest_framework.test import APIClient
from rest_framework.response import Response
class CoreTestCase(unittest.TestCase):
@patch('core.views.CoreViewSet.list')
def test_response(self, mock_get):
mock_get.return_value = Response([{'hello': 'world'}])
client = APIClient()
response = client.get('/core/')
print(response.data)
Which achieved the desired result and I was just passing in an array of objects (or list of dicts).
However, I'm not sure this was the correct way of handling this and if Mock()
should have been used instead. I can honestly say I haven't been able to figure out how to use Mock()
or MagicMock()
correctly, or find a tutorial that explains it clearly, so my attempts at using it with:
mock_get.return_value = Mock([{'hello': 'world'}])
Just resulted in:
TypeError: 'module' object is not callable
Any suggestions about how this test should be implemented?
AssertionError: Expected a
Response
,HttpResponse
orHttpStreamingResponse
to be returned from the view, but received a<class 'list'>
This error comes from isinstance
assertion here.
If you want to use Mock
or MagicMock
to mock Response
and pass isinstance
check, you can use spec
or spec_set
parameter when creating a mock response.
class CoreTestCase(unittest.TestCase):
@patch('core.views.CoreViewSet.list')
def test_response(self, mock_get):
mock_get.return_value = Mock(spec=Response, data=[{'hello': 'world'}])
...
When creating a Mock
or Magic
, you should pass the property name of what you want to mock as keyword arguments. In this case, you want to mock Response.data
, therefore you should set Mock(data=<DATA_VALUE>)
. Otherwise, the value will be passed to Mock
positional arguments.
The official python documentation also provides clear examples of how to use mock
module here.