In our Django project, we have some API views that are defined in urls.py
like this:
path('api/calendar/calendar_data', calendar_api.serve_data),
and our calendar_api
is an instance of CalendarAPI
, which is instantiated above:
from main.calendar_api import CalendarAPI
from caldav import DAVClient
...
calendar_api = CalendarAPI(client=DAVClient(...))
In the CalendarAPI class we have a method that fetches data from a remote CalDAV calendar using the caldav library like so:
class CalendarAPI(ApiEndpoint):
...
def __init__(self, client):
self.caldav_client = client
def _get_event_list(self):
return self.caldav_client.principal().calendars()[0].events()
We wish to mock this method in a way such that _get_event_list returns a predefined array.
Our test case looks like this:
from unittest.mock import patch
from django.test import SimpleTestCase
class TestCalendar(SimpleTestCase):
@patch('main.urls.CalendarAPI')
def test_response_format(self, calendarapi_mock):
calendarapi_mock._get_event_list.return_value = mocked_calendar_events
response = self.client.get('/api/calendar/calendar_data', format='json')
# fails test if response does not match mocked_calendar_events
self._compareResponse(response, mocked_calendar_events)
No matter what we try, we can't get mocking to work. If anyone knows of a better way to instantiate classes in urls.py
in light of mocking, please let us know!
This always gets me as well. To mock a method on an instance of
CalendarAPI
, you need to mock the method on thereturn_value
of the mock (calendarapi_mock.return_value
).With
calendarapi_mock._get_event_list.return_value
, you're mocking the method on theCalendarAPI
class instead, i.e.CalendarAPI._get_event_list()
.So instead of
use: