Django UnitTest with Mock
Solution 1
What your are looking for is patch
from unittest.mock
. You can patch call_external_api()
by a MagicMock()
object.
Maybe you want to patch call_external_api()
for all your tests in class. patch
give to you essentialy two way to do it
- decorate the test class
- use
start()
andstop()
insetUp()
andtearDown()
respectively
Decorate a class by patch
decorator is like decorate all test methods (see documentation for details) and the implementation will be very neat. Follow example assume that your view is in my_view
module.
@patch("my_view.call_external_api", autospec=True)
class MyTest(unittest.TestCase):
def setUp(self):
self.client = Client()
def test_get_data(self, mock_call_external_api):
self.client.get('/example/url/')
self.assertTrue(mock_call_external_api.called)
More sophisticate examples can be build and you can check how you call mock_call_external_api
and set return value or side effects for your API.
I don't give any example about start and stop way to do it (I don't really like it) but I would like to spend some time on two details:
- I assumed that in your
my_view
module you definecall_external_api
or you import it byfrom my_API_module import call_external_api
otherwise you should pay some attention on Where to patch - I used
autospec=True
: IMHO it should be used in every patch call and documentation explain why very well
Solution 2
You can mock the call_external_api()
method when testing the classed based view with something like this:
import modulea
import unittest
from mock import Mock
class ExampleTestCase(unittest.TestCase):
def setUp(self):
self.call_external_api = modulea.call_external_api
def tearDown(self):
modulea.call_external_api = self.call_external_api
def get_data(self):
modulea.call_external_api = Mock(return_value="foobar")
modulea.call_external_api()
## do something else
Jerry Meng
Updated on June 04, 2022Comments
-
Jerry Meng almost 2 years
I am writing an Unit-Test for a Django class-based view.
class ExampleView(ListView): def get_context_data(self, **kwargs): context = super(EampleView, self).get_context_data(**kwargs) ## do something else def get_queryset(self, **kwargs): return self.get_data() def get_data(self): call_external_API() ## do something else
The key issue is that
call_external_API()
inget_data()
.When I am writing Unit-test, I don't really want to call external API to get data. First, that will cost my money; second, I can easily test that API in another test file.
I also can easily test this
get_data()
method by having an unit-test only for it and mock the output ofcall_external_API()
.However, when I test this whole class-based view, I simply will do
self.client.get('/example/url/')
and check the status code and context data to verify it.
In this case, how do I mock this
call_external_API()
when I am testing the whole class-based view?