httpx.MockTransport介绍(HTTPX官方提供的传输层实现,不发送HTTP请求,把请求交给自定义函数处理)与unittest.mock的区别、RESPX、模拟接口模拟http mock
开始写代码。首先是源适配器框架(依赖注入 httpx client 以便测试用 MockTransport 全覆盖)
文章目录
- HTTPX MockTransport 完全指南:优雅地 Mock HTTP 请求
- 什么是 MockTransport
- 为什么 HTTPX 要设计 Transport
- 最简单的示例
- handler 的工作原理
- 返回 JSON
- 返回文本
- 返回 HTML
- 返回图片
- 模拟不同状态码
- 根据 URL 返回不同结果
- 根据请求方法返回不同结果
- 检查请求 Header
- 检查 Query 参数
- 检查 POST Body
- 模拟接口异常
- AsyncClient 中使用 MockTransport
- 在 pytest 中使用
- MockTransport 与 unittest.mock 的区别
- MockTransport 与 RESPX 的区别
- 最佳实践
- 总结
HTTPX MockTransport 完全指南:优雅地 Mock HTTP 请求
在 Python 项目中,我们经常需要测试调用第三方 API 的代码,例如:
- 调用 OpenAI API
- 调用 GitHub API
- 调用支付接口
- 调用天气接口
- 微服务之间的 HTTP 调用
如果测试过程中真的去访问互联网,会带来很多问题:
- 网络不稳定导致测试失败
- API 有调用次数限制
- 请求速度慢
- 需要配置各种 Token
- 测试数据不可控
因此,Mock HTTP 请求几乎是所有大型 Python 项目的标准实践。
而对于使用 HTTPX 的项目来说,官方提供了一个非常优雅的解决方案:
httpx.MockTransport
本文将全面介绍它的使用方法、工作原理以及最佳实践。
什么是 MockTransport
MockTransport 是 HTTPX 官方提供的一种 Transport(传输层)实现。
它不会真正发送 HTTP 请求,而是把请求交给你自己编写的函数处理。
整个流程如下:
Client.get()
│
▼
MockTransport
│
▼
你的 handler()
│
▼
返回 Response
│
▼
Client 收到 Response
例如:
client.get("https://api.github.com/users/octocat")
正常情况下:
Client
│
▼
Internet
│
▼
GitHub API
│
▼
Response
使用 MockTransport 后:
Client
│
▼
MockTransport
│
▼
handler(request)
│
▼
Response(status_code=200)
整个过程中:
- 不访问互联网
- 不需要 DNS
- 不需要 Token
- 不需要服务器
为什么 HTTPX 要设计 Transport
HTTPX 的底层采用了 Transport 抽象层。
可以理解为:
Client
↓
Transport
↓
TCP Socket
默认情况下:
client = httpx.Client()
实际上使用的是:
HTTPTransport
而:
client = httpx.Client(
transport=MockTransport(...)
)
则替换了真正的网络层。
所以:
你的业务代码完全不知道请求有没有真正发出去。
这就是依赖抽象(Dependency Inversion)的思想。
最简单的示例
例如:
import httpx
def handler(request):
return httpx.Response(
status_code=200,
json={"message": "hello"}
)
transport = httpx.MockTransport(handler)
client = httpx.Client(transport=transport)
response = client.get("https://example.com")
print(response.json())
输出:
{'message': 'hello'}
整个过程没有任何网络请求。
handler 的工作原理
handler 接收一个:
httpx.Request
例如:
def handler(request):
print(request.method)
print(request.url)
return httpx.Response(200)
运行:
client.get("https://example.com/test")
输出:
GET
https://example.com/test
说明:
请求对象是真实构造出来的。
你可以检查:
- URL
- Method
- Header
- Query
- Cookie
- Body
返回 JSON
最常见的情况就是返回 JSON。
def handler(request):
return httpx.Response(
status_code=200,
json={
"id": 1,
"name": "Alice"
}
)
客户端:
response = client.get("/users/1")
print(response.json())
输出:
{
"id": 1,
"name": "Alice"
}
返回文本
def handler(request):
return httpx.Response(
status_code=200,
text="Hello World"
)
读取:
print(response.text)
返回 HTML
def handler(request):
return httpx.Response(
200,
headers={
"Content-Type": "text/html"
},
text="<h1>Hello</h1>"
)
返回图片
例如:
def handler(request):
return httpx.Response(
200,
content=b"\x89PNG..."
)
读取:
response.content
模拟不同状态码
例如:
404:
def handler(request):
return httpx.Response(404)
500:
def handler(request):
return httpx.Response(500)
401:
def handler(request):
return httpx.Response(401)
429:
def handler(request):
return httpx.Response(429)
这样就可以测试各种异常处理逻辑。
根据 URL 返回不同结果
例如:
def handler(request):
if request.url.path == "/users":
return httpx.Response(
200,
json=[{"id": 1}]
)
if request.url.path == "/login":
return httpx.Response(
200,
json={"token": "abc"}
)
return httpx.Response(404)
这样一个 MockTransport 就可以模拟整个 REST API。
根据请求方法返回不同结果
def handler(request):
if request.method == "GET":
return httpx.Response(
200,
json={"action": "read"}
)
if request.method == "POST":
return httpx.Response(
201,
json={"action": "create"}
)
return httpx.Response(405)
检查请求 Header
例如:
def handler(request):
token = request.headers.get("Authorization")
if token != "Bearer abc":
return httpx.Response(401)
return httpx.Response(200)
测试认证逻辑非常方便。
检查 Query 参数
def handler(request):
page = request.url.params.get("page")
return httpx.Response(
200,
json={
"page": page
}
)
调用:
client.get("/users?page=2")
返回:
{
"page": "2"
}
检查 POST Body
JSON:
import json
def handler(request):
body = json.loads(request.content)
return httpx.Response(
200,
json=body
)
调用:
client.post(
"/users",
json={
"name": "Tom"
}
)
返回:
{
"name": "Tom"
}
模拟接口异常
例如模拟服务器错误:
def handler(request):
return httpx.Response(500)
或者模拟超时等网络异常:
def handler(request):
raise httpx.ConnectTimeout("Connection timed out")
业务代码便可以验证重试、降级或异常处理是否符合预期。
AsyncClient 中使用 MockTransport
异步客户端同样支持。
import httpx
import asyncio
def handler(request):
return httpx.Response(
200,
json={"ok": True}
)
transport = httpx.MockTransport(handler)
async def main():
async with httpx.AsyncClient(
transport=transport
) as client:
r = await client.get("/")
print(r.json())
asyncio.run(main())
接口与同步版本保持一致。
在 pytest 中使用
例如:
import httpx
def handler(request):
return httpx.Response(
200,
json={"success": True}
)
def test_api():
client = httpx.Client(
transport=httpx.MockTransport(handler)
)
response = client.get("/")
assert response.status_code == 200
assert response.json()["success"]
无需启动任何 Mock Server,即可完成测试。
MockTransport 与 unittest.mock 的区别
很多开发者会直接使用 unittest.mock.patch() 来 Mock HTTP 请求,但两者关注点不同。
| 对比项 | MockTransport | unittest.mock |
|---|---|---|
| Mock 层级 | HTTP 传输层 | 任意 Python 对象 |
| 是否保留 HTTP 请求对象 | ✅ 是 | ❌ 通常需要自行构造 |
| 是否模拟完整 HTTP 行为 | ✅ 是 | ❌ 取决于 Mock 内容 |
| 是否依赖 HTTPX | ✅ 是 | ❌ 通用 |
| 更适合 | HTTP 客户端测试 | 单元测试、依赖替换 |
如果你的代码使用 HTTPX 发起请求,MockTransport 往往更自然,因为它保持了 HTTP 请求/响应模型。
MockTransport 与 RESPX 的区别
除了官方提供的 MockTransport,社区还有一个广受欢迎的库 RESPX,专门用于 HTTPX 请求 Mock。
| 对比项 | MockTransport | RESPX |
|---|---|---|
| 来源 | HTTPX 官方 | 第三方库 |
| 配置方式 | 编写 handler | 声明式路由 |
| 学习成本 | 较低 | 中等 |
| 适合复杂接口 Mock | 一般 | 更强 |
| 是否需要额外依赖 | 否 | 是 |
对于简单或中等规模的测试,MockTransport 已经足够;如果需要大量接口、复杂匹配规则或断言请求调用次数,RESPX 会更方便。
最佳实践
1. 不要在 handler 中写过于复杂的业务逻辑
handler 的职责应该是模拟接口行为,而不是复制真实服务的全部实现,否则测试本身会变得难以维护。
2. 一个测试只关注一种场景
例如分别编写:
- 成功响应
- 404
- 401
- 500
- 超时
- 返回非法 JSON
这样每个测试的目的都很明确。
3. 将 Mock 数据集中管理
对于大型项目,可以把常见响应抽取成独立模块,例如:
tests/
mocks/
github.py
openai.py
payment.py
避免在多个测试文件中重复构造相同的响应。
4. 尽量通过依赖注入传递 Client
不要在业务代码内部直接创建 httpx.Client(),而是允许传入客户端实例:
def fetch_user(user_id: int, client: httpx.Client) -> dict:
response = client.get(f"/users/{user_id}")
response.raise_for_status()
return response.json()
这样在测试时即可注入使用 MockTransport 的客户端,而生产环境则传入真实客户端,代码无需修改。
总结
httpx.MockTransport 是 HTTPX 官方提供的轻量级 HTTP Mock 方案,通过替换底层传输层,让应用代码无需真正访问网络即可获得可控的响应。相比直接使用 unittest.mock 替换方法,它保留了完整的 HTTP 请求与响应模型,更贴近真实运行环境;相比第三方 Mock Server,它无需启动额外服务,执行速度更快,维护成本也更低。
对于使用 HTTPX 的项目,推荐将 MockTransport 与 pytest、依赖注入相结合,用于覆盖成功、异常、超时、认证失败等各种场景,从而构建快速、稳定且可重复执行的自动化测试体系。在大多数单元测试和轻量级集成测试中,它已经能够满足绝大多数需求,是 HTTPX 官方推荐且符合企业最佳实践的 Mock 方式。
更多推荐


所有评论(0)