Introduction to HTTPretty: Mocking HTTP Requests in Python
HTTPretty is a Python library for testing that enables lightweight, precise mocking of HTTP/HTTPS requests and responses, offering isolation, speed, complex scenario simulation, and data protection, illustrated with five practical code examples covering token retrieval, webhook handling, error simulation, timeout testing, and pagination.
HTTPretty is a Python library designed for testing environments, allowing lightweight and precise mocking of HTTP(s) requests and responses without real network connections.
Key advantages include isolating tests from unstable external services, accelerating test cycles, easily simulating edge cases such as timeouts and error status codes, and protecting sensitive data by using mock responses.
The article provides five code examples demonstrating common usage scenarios.
Example 1: Mocking WeChat access_token API response
import requests
from httpretty import HTTPretty, httprettified
# 微信 API 地址
WECHAT_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token"
@httprettified
def test_get_access_token():
# 预设模拟响应
expected_response = '{"access_token":"your_token","expires_in":7200}'
HTTPretty.register_uri(
HTTPretty.GET,
WECHAT_TOKEN_URL,
body=expected_response,
status=200,
content_type="application/json",
)
# 调用实际获取 access_token 的函数(假设已实现)
access_token = get_access_token(appid, secret)
# 断言返回的 access_token 与模拟响应一致
assert access_token == "your_token"Example 2: Mocking a user subscription webhook
import json
from httpretty import HTTPretty, httprettified
# 事件处理器 URL
EVENT_HANDLER_URL = "https://your_server.com/wechat/webhook"
@httprettified
def test_handle_subscribe_event():
# 构造关注事件的 JSON 数据
event_payload = {
"ToUserName": "your_appid",
"FromUserName": "openid",
"Event": "subscribe",
}
HTTPretty.register_uri(
HTTPretty.POST,
EVENT_HANDLER_URL,
body=json.dumps(event_payload),
content_type="application/json",
)
# 调用实际的事件处理器函数(假设已实现)
handle_subscribe_event(json.dumps(event_payload))
# 验证处理逻辑,如检查数据库中用户状态是否已更新为已关注
assert UserSubscription.query.filter_by(openid="openid").one().is_subscribedExample 3: Simulating a 404 Not Found error
from httpretty import HTTPretty, httprettified
# 需要模拟失败响应的 API 地址
API_URL = "https://api.example.com/resource"
@httprettified
def test_handle_not_found_error():
HTTPretty.register_uri(
HTTPretty.GET,
API_URL,
status=404,
body="Resource not found",
content_type="text/plain",
)
# 调用实际请求函数(假设已实现)
response = make_api_request()
# 断言请求返回的状态码和处理结果
assert response.status_code == 404
assert response.content == b"Resource not found"
assert error_handling_function(response) is not NoneExample 4: Simulating delayed response to test timeout handling
import time
from httpretty import HTTPretty, httprettified
# 需要模拟延迟响应的 API 地址
DELAYED_API_URL = "https://slow-api.example.com/data"
@httprettified
def test_request_timeout_handling():
HTTPretty.register_uri(
HTTPretty.GET,
DELAYED_API_URL,
body='{"key": "value"}',
content_type="application/json",
status=200,
)
HTTPretty.enable_net_connect(False) # 禁止真实网络连接
# 设置模拟响应延迟 5 秒
HTTPretty.register_uri(
HTTPretty.GET,
DELAYED_API_URL,
body='{"key": "value"}',
content_type="application/json",
status=200,
adding_headers={"X-Delay": "5"},
)
# 调用实际请求函数(假设已实现),并设置超时时间为 3 秒
start_time = time.time()
try:
response = make_api_request(timeout=3)
except requests.exceptions.Timeout:
elapsed_time = time.time() - start_time
assert elapsed_time >= 3 # 确保超时触发
return # 跳过后续断言,因为预期会抛出异常
assert False, "Expected a Timeout exception, but it was not raised."Example 5: Mocking paginated API responses
import json
from httpretty import HTTPretty, httprettified
# 分页查询 API 地址
PAGINATION_API_URL = "https://api.example.com/items"
@httprettified
def test_pagination_logic():
# 预设第一页响应
first_page_response = {
"items": [{"id": 1, "name": "Item 1"}, {"id": 2, "name": "Item 2"}],
"next_page": "https://api.example.com/items?page=2",
}
HTTPretty.register_uri(
HTTPretty.GET,
PAGINATION_API_URL,
body=json.dumps(first_page_response),
status=200,
content_type="application/json",
)
# 预设第二页响应
second_page_response = {
"items": [{"id": 3, "name": "Item 3"}, {"id": 4, "name": "Item 4"}],
"next_page": None,
}
HTTPretty.register_uri(
HTTPretty.GET,
first_page_response["next_page"],
body=json.dumps(second_page_response),
status=200,
content_type="application/json",
)
# 调用实际分页查询函数(假设已实现)
all_items = fetch_all_items(PAGINATION_API_URL)
# 验证所有项目是否按预期顺序加载
expected_items = [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"},
{"id": 3, "name": "Item 3"},
{"id": 4, "name": "Item 4"},
]
assert all_items == expected_itemsThese five examples show how to use HTTPretty in various scenarios—retrieving a WeChat access token, handling a subscription webhook, simulating a 404 error, testing timeout handling with delayed responses, and mocking paginated API responses—helping developers improve test efficiency and code quality.
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.