Mocking API request tests for Wagtail… with KanyeRest

from home.api_content import KanyeRest
from wagtail.core.models import Page

class HomePage(Page):
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
context["kanye_quote"] = KanyeRest().get_data()
return context
Homepage example showing a quote… I know, Kanye is a bit… creative.
Example of data from
import json
import logging

import requests
from django.conf import settings

logger = logging.getLogger(__name__)

class KanyeParse:
def __init__(self, data): = data

# A very simple parser
def get_parsed_data(self):
parsed_data = json.loads(
return parsed_data["quote"]

class KanyeRest:
def __init__(self): = None
self.url = ""

def get_url(self):
return self.url

def fetch_data(self):
response = requests.get(url=self.url) = response.content
except requests.exceptions.Timeout:
logger.exception(f"Timeout occurred")
except Exception:
logger.exception(f"Error occurred")

def get_data(self):
""" If there is data, parse it, otherwise return an empty list """ = self.fetch_data()
if = KanyeParse(
return []
  • How does the code handle a Timeout?
  • Does the data go through the parser as expected
  • If there are Exceptions, will the homepage still render?

Testing the API is up

Here, I’m setting up some values to test, seen as though I don’t want to use the live API because data changes with each request. Then a quick test_fetch to check the live API is responding.

class TestKanye(TestCase):
def setUp(self):
self.expected_api_data = {"quote": "All you have to be is yourself"}
self.expected_parsed_data = "I want the world to be better! All I want is positive! All I want is dopeness!"
self.default_data = [{"quote": "This is me, not Kayne"}]

def test_fetch(self):
url = KanyeRest().get_url()
response = requests.get(url, timeout=5)
self.assertEqual(response.status_code, 200)

Testing a fetch with mocked data

Using mock.patch can replace methods and classes with ones you define specifically for tests. Here I’m saying “Don’t use the fetch_data method from my KanyeRest() class, instead use mock_fetched_data”

# Data changes on each request so mock it
@mock.patch("home.api_content.KanyeRest.fetch_data", side_effect=mocked_fetch_data)
def test_fetch_with_example_data(self, mocked_fetch_data):
data = KanyeRest().get_data()
lf.assertEqual(data, self.expected_parsed_data)
def mocked_fetch_data():
data = json.dumps(
"quote": "I want the world to be better! All I want is positive! All I want is dopeness!"
return data

Testing the default data is used with a Timeout

Here with mock.patch, I’m mocking the get request used by requests.get. Doing this allows me to define a ‘side_effect’, and that can be a Timeout exception.

def test_data_if_timeout(self, mock_get):
""" If a timeout is caught we should be getting the default data"""
mock_get.side_effect = Timeout
data = KanyeRest().get_data()
self.assertEqual(data, self.default_data)

But does the page render with a Timeout?

Yep, this test is similar to the test above, we just check the rendering of the page:

def test_page_renders_with_timeout(self, mock_get):
""" If there is a timeout for the request when the page loads,
ensure the page still renders with the default data"""
home_page = HomePage.objects.first()
mock_get.side_effect = Timeout
response = self.client.get("/")
self.assertTemplateUsed(response, "home/home_page.html")
self.assertEqual(response.render().status_code, 200)



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store