How to Encapsulate and Call Mock Services in pytest
This tutorial demonstrates how to use pytest together with Python's unittest.mock module to mock external HTTP requests, covering fixture creation, mock response setup, and writing test cases for both successful and failed API calls.
Install pytest using pip; unittest.mock is part of the Python standard library.
Create the module to test, e.g., my_module.py with a fetch_data function that uses requests.get to retrieve JSON data and raises HTTPError on failure.
Create a test file test_my_module.py.
Import pytest, unittest.mock's MagicMock and patch, and fetch_data from my_module.
Define a fixture mock_requests_get that patches requests.get and yields the mock object.
Create a helper function setup_mock_response(mock_get, status_code=200, json_data=None) that configures the mock to return a MagicMock response with the given status code and JSON data, and simulates HTTPError for status codes >=400.
Write test cases: test_fetch_data_success sets up a mock response with status 200 and JSON data, calls fetch_data, asserts the returned value matches the data, and verifies that mock_requests_get was called once with the expected URL.
Write test_fetch_data_failure that sets up a mock response with status 404, calls fetch_data inside a pytest.raises context for HTTPError, and asserts the mock was called correctly.
Run the tests with the command pytest test_my_module.py.
Explanation: patch temporarily replaces requests.get with a mock; MagicMock records calls and allows setting return values and side effects; setup_mock_response simplifies configuring mock responses; assert_called_once_with verifies the mock was invoked with the correct arguments.
# my_module.py
import requests
def fetch_data(url):
"""
从给定的 URL 获取数据。
参数:
url (str): API 端点的 URL。
返回:
dict: API 返回的 JSON 数据。
异常:
requests.exceptions.HTTPError: 如果 HTTP 请求失败。
"""
response = requests.get(url)
response.raise_for_status() # 如果 HTTP 请求失败,抛出异常
return response.json() # test_my_module.py
import pytest
from unittest.mock import MagicMock, patch
from my_module import fetch_data
@pytest.fixture
def mock_requests_get():
"""
使用 pytest 的 fixture 来模拟 requests.get 方法。
返回:
MagicMock: 模拟的 requests.get 对象。
"""
with patch('requests.get') as mock_get:
yield mock_get
def setup_mock_response(mock_get, status_code=200, json_data=None):
"""
设置 mock 响应。
参数:
mock_get (MagicMock): 模拟的 requests.get 对象。
status_code (int): 响应的状态码,默认为 200。
json_data (dict): 响应的 JSON 数据,默认为 None。
"""
mock_response = MagicMock()
mock_response.status_code = status_code # 设置状态码
if json_data is not None:
mock_response.json.return_value = json_data # 设置 JSON 响应数据
if status_code >= 400:
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError("请求失败") # 设置异常
# 设置 mock_get 的返回值为模拟的响应对象
mock_get.return_value = mock_response
def test_fetch_data_success(mock_requests_get):
"""
测试 fetch_data 函数在成功情况下的行为。
"""
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")
def test_fetch_data_failure(mock_requests_get):
"""
测试 fetch_data 函数在失败情况下的行为。
"""
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")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.