This video is available to students only

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.

stock-app/tests/test_stock.py
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"}]}
No discussions yet