本文目录导读:

对于测试外部API,VCR(如vcrpy)是非常推荐的方案,但并不是唯一选择,具体是否使用取决于你的测试目标:
✅ 推荐使用VCR的场景
需要录制/重放HTTP请求
import vcr
import requests
# 录制API响应
with vcr.use_cassette('fixtures/github_api.yaml'):
response = requests.get('https://api.github.com/users/octocat')
assert response.status_code == 200
assert 'login' in response.json()
测试需要可重复、确定性
- 避免网络波动导致测试失败
- 不依赖外部服务可用性
- 加速测试执行(本地重放比网络请求快10-100倍)
需要模拟特定响应场景
import vcr
# 模拟错误响应
with vcr.use_cassette('fixtures/error_response.yaml') as cassette:
# 手动修改录制的响应
cassette.responses[0].status = {'code': 500, 'message': 'Server Error'}
response = requests.get('https://api.example.com/data')
assert response.status_code == 500
❌ 不适合使用VCR的场景
测试API的实时状态
- 检查服务是否正常运行(用健康检查)
- 验证最新数据是否正确(用集成测试)
安全敏感测试
- 录制的请求可能包含API密钥(虽然VCR可以过滤)
- 测试与真实环境的交互
需要测试网络异常
# 使用responses库模拟网络错误
import responses
import requests
@responses.activate
def test_network_timeout():
responses.add(
responses.GET, 'https://api.example.com',
body=requests.Timeout('Connection timed out')
)
with pytest.raises(requests.Timeout):
requests.get('https://api.example.com')
🔧 替代方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| VCR (vcrpy) | 自动录制、可重放、支持多种HTTP库 | 录制文件可能很大、更新需要重新录制 | 大多数API测试 |
| responses | 轻量、完全控制响应、无文件依赖 | 需要手动定义所有响应 | 简单、确定性测试 |
| mocks (unittest.mock) | 完全控制、无需HTTP | 需要深入理解业务逻辑 | 单元测试、内部逻辑 |
| WireMock | 支持Stub/Record/Proxy、更专业 | 需要额外服务、配置复杂 | 微服务集成测试 |
| 直接调用 | 真实、简单 | 依赖网络、不稳定、慢 | 冒烟测试、健康检查 |
🎯 最佳实践建议
对于Python测试外部API:
# 1. 使用vcrpy + pytest-vcr
import pytest
import vcr
# 在conftest.py中配置
@pytest.fixture(scope='module')
def vcr_config():
return {
'filter_headers': ['Authorization'], # 过滤敏感信息
'record_mode': 'new_episodes', # 新请求才录制
'ignore_localhost': True,
}
# 2. 分层测试策略
class TestUserAPI:
"""用户API测试"""
@vcr.use_cassette('fixtures/user_api.yaml')
def test_get_user(self):
"""使用VCR录制/重放"""
response = requests.get('https://api.example.com/users/1')
assert response.status_code == 200
def test_get_user_live(self):
"""集成测试(可选)"""
response = requests.get('https://api.example.com/users/1')
assert response.status_code == 200
@responses.activate
def test_get_user_timeout(self):
"""模拟异常"""
responses.add(responses.GET, 'https://api.example.com/users/1',
body=TimeoutError())
with pytest.raises(TimeoutError):
requests.get('https://api.example.com/users/1')
# 3. 配置VCR的最佳实践
vcr = vcr.VCR(
serializer='yaml',
cassette_library_dir='fixtures/cassettes',
record_mode='once', # 只录制一次,之后重放
match_on=['uri', 'method'], # 匹配请求
filter_headers=['authorization', 'cookie'],
filter_query_parameters=['token', 'key'],
)
📊 总结建议
用VCR当:
- ✅ 你希望测试稳定、快速、可重复
- ✅ 你依赖外部API,但不想每次测试都真实调用
- ✅ 你需要模拟特定场景(错误、延迟、特定数据)
不用VCR当:
- ❌ 你需要测试API的最新状态
- ❌ 你的API响应非常简单或可预测
- ❌ 你只是想检查API是否可访问
推荐组合:
- 单元测试: VCR + responses(混合使用)
- 集成测试: 真实调用(选择性)
- CI/CD: VCR(避免网络依赖)
- 监控: 真实调用(检查服务健康)
对于大多数Python项目测试外部API,强烈推荐使用VCR,配合responses处理边界情况,用真实调用做少量集成测试。