Getting to 100% Code Coverage With Flask Python Testing
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Mocking HTTP Responses
We've tested the home blueprint, now let's add tests for the routes in the stock blueprint. Since this route actually issues real network requests to our stock ticker API, we can't be sure of it's consistency. For example, if we wanted to assert that the page actually displayed the stock price, we wouldn't be sure what string to look for because the real stock price is constantly changing. Instead, the approach we'll take is to "mock" or fake the data from the API to look like some data we've essentially hard-coded. If you've never done this before, this might sound odd but our goal with automated tests is not to test the external API, but rather our own code.
class MockPrice:
@staticmethod
def json():
return {"price": 42.0}
Once we have our desired hard-coded result we need to monkey patch over some functions to return objects that we've already defined. This uses a built in fixture of PyTest called monkeypath
which allows us to hard code the return value of functions. Here we're replacing requests.get
with the mock_get
function.
def test_stock_quote(client, monkeypatch):
def mock_get(*args, **kwargs):
return MockPrice()
monkeypatch.setattr(requests, "get", mock_get)
response = client.get(url_for('stock.view_stock', ticker="APPL"))
assert response.status_code == 200
assert b'Price: $42' in response.data
assert b'portfolio' in response.data
In later chapters, we will cover how to do fine-grained mocking of HTTP requests.
Expecting Failure
If we want to test that our code actually does raise an exception, we can wrap the call in a pytest.raises(expected_exception)
block.
def test_unknown_financials(client, monkeypatch):
def mock_empty_response(*args, **kwargs):
return MockNotFound()
monkeypatch.setattr(requests, "get", mock_empty_response)
with pytest.raises(KeyError):
response = client.get(url_for('stock.financials', ticker="UNKNONW"))
You can similarly test the rest of the blueprint with some additional tests.
from flask import url_for
import requests
import pytest
class MockPrice:
@staticmethod
def json():
return {"price": 42.0}
class MockFinancials:
@staticmethod
def json():
return {"financials": [{'date': '2019-01-01', "Revenue": '100.00',
'Revenue Growth': "0.1", "EPS": "2.2"}]}
This lesson preview is part of the Fullstack Flask: Build a Complete SaaS App with Flask course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack Flask: Build a Complete SaaS App with Flask, plus 70+ \newline books, guides and courses with the \newline Pro subscription.