How to Mock External Services in pytest Using unittest.mock
This guide explains how to install pytest, create a module with a function that calls an external API, and use unittest.mock fixtures and helper functions to mock requests.get for both successful and failing responses, then run the tests with pytest.
When writing unit tests with pytest , you often need to mock external services or functions. The standard library module unittest.mock provides powerful mocking capabilities that integrate smoothly with pytest .
1. Install dependencies
Make sure pytest is installed (the unittest.mock module is included in the Python standard library).
pip install pytest2. Create the module to be tested
Assume a file my_module.py with a function fetch_data that calls an external API.
# my_module.py
import requests
def fetch_data(url):
"""Fetch data from the given URL.
Args:
url (str): API endpoint URL.
Returns:
dict: JSON data returned by the API.
Raises:
requests.exceptions.HTTPError: If the HTTP request fails.
"""
response = requests.get(url)
response.raise_for_status() # Raise if the request failed
return response.json()3. Create the test file
In test_my_module.py , import pytest , MagicMock , patch , and the function to test.
# test_my_module.py
import pytest
from unittest.mock import MagicMock, patch
from my_module import fetch_data3.1 Define a fixture to set up the mock object
# Define a fixture to set up the mock object
@pytest.fixture
def mock_requests_get():
"""Use a pytest fixture to mock
requests.get
."""
with patch('requests.get') as mock_get:
yield mock_get3.2 Encapsulate mock behavior
# Encapsulate mock behavior
def setup_mock_response(mock_get, status_code=200, json_data=None):
"""Configure the mock response.
Args:
mock_get (MagicMock): The mocked
requests.get
object.
status_code (int): HTTP status code (default 200).
json_data (dict): JSON payload to return (default None).
"""
mock_response = MagicMock()
mock_response.status_code = status_code
if json_data is not None:
mock_response.json.return_value = json_data
if status_code >= 400:
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError("Request failed")
mock_get.return_value = mock_response3.3 Write test cases
# Test case: successful request
def test_fetch_data_success(mock_requests_get):
"""Test
fetch_data
when the request succeeds."""
setup_mock_response(mock_requests_get, status_code=200, json_data={"key": "value"})
result = fetch_data("http://example.com/api/data")
assert result == {"key": "value"}
mock_requests_get.assert_called_once_with("http://example.com/api/data")
# Test case: failed request
def test_fetch_data_failure(mock_requests_get):
"""Test
fetch_data
when the request fails."""
setup_mock_response(mock_requests_get, status_code=404)
with pytest.raises(requests.exceptions.HTTPError):
fetch_data("http://example.com/api/data")
mock_requests_get.assert_called_once_with("http://example.com/api/data")4. Run the tests
Execute the tests from the terminal:
pytest test_my_module.pyExplanation
Installation: pip install pytest installs pytest; unittest.mock is built‑in.
Module creation: fetch_data retrieves JSON from a URL and raises HTTPError on failure.
Test file: The fixture mock_requests_get patches requests.get .
Helper function: setup_mock_response configures status code and JSON payload for the mock.
Test cases: Verify correct behavior for both successful and error responses, and assert that requests.get is called with the expected URL.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.