本文目录导读:

在Python中Mock外部API有多种方法,我来介绍最常用的几种:
使用 unittest.mock(标准库)
patch 装饰器
import requests
from unittest.mock import patch
import unittest
def get_user_data(user_id):
response = requests.get(f'https://api.example.com/users/{user_id}')
return response.json()
class TestUserAPI(unittest.TestCase):
@patch('requests.get')
def test_get_user_data(self, mock_get):
# 设置模拟响应
mock_response = mock_get.return_value
mock_response.status_code = 200
mock_response.json.return_value = {
'id': 1,
'name': 'John Doe',
'email': 'john@example.com'
}
# 调用被测试函数
result = get_user_data(1)
# 验证结果
self.assertEqual(result['name'], 'John Doe')
self.assertEqual(result['email'], 'john@example.com')
# 验证API被正确调用
mock_get.assert_called_once_with('https://api.example.com/users/1')
patch 上下文管理器
import requests
from unittest.mock import patch
def get_temperature(city):
response = requests.get(f'https://api.weather.com/temp/{city}')
if response.status_code == 200:
return response.json()['temperature']
return None
# 使用上下文管理器
with patch('requests.get') as mock_get:
mock_response = mock_get.return_value
mock_response.status_code = 200
mock_response.json.return_value = {'temperature': 25.5}
result = get_temperature('Beijing')
assert result == 25.5
手动创建Mock对象
from unittest.mock import Mock, patch
import requests
def process_external_api(url, data):
response = requests.post(url, json=data)
return response.json()
# 创建完整的Mock响应
mock_response = Mock()
mock_response.status_code = 201
mock_response.json.return_value = {'status': 'success', 'id': 123}
with patch('requests.post', return_value=mock_response):
result = process_external_api('https://api.example.com/data', {'key': 'value'})
print(result) # {'status': 'success', 'id': 123}
使用第三方库
使用 responses 库
import responses
import requests
@responses.activate
def test_api():
# 注册模拟响应
responses.add(
responses.GET,
'https://api.example.com/users/1',
json={'id': 1, 'name': 'John'},
status=200
)
# 调用实际的requests
response = requests.get('https://api.example.com/users/1')
data = response.json()
assert data['name'] == 'John'
assert response.status_code == 200
使用 mocket 库
from mocket import Mocket, mocketize
import requests
@mocketize
def test_with_mocket():
# 注册模拟响应
Mocket.register(
url='https://api.example.com/users',
method='GET',
body='{"users": ["Alice", "Bob"]}',
headers={'Content-Type': 'application/json'}
)
# 正常的requests调用
response = requests.get('https://api.example.com/users')
data = response.json()
assert data['users'] == ['Alice', 'Bob']
高级Mock技巧
Mock带认证的API
from unittest.mock import patch
class APIClient:
def __init__(self, token):
self.token = token
self.session = requests.Session()
self.session.headers.update({'Authorization': f'Bearer {token}'})
def get_data(self):
response = self.session.get('https://api.example.com/data')
return response.json()
def test_api_client():
with patch.object(requests.Session, 'get') as mock_get:
mock_response = mock_get.return_value
mock_response.json.return_value = {'data': 'test'}
client = APIClient('fake_token')
result = client.get_data()
assert result['data'] == 'test'
mock_get.assert_called_once_with('https://api.example.com/data')
Mock异步API调用
import aiohttp
import asyncio
from unittest.mock import AsyncMock, patch
async def fetch_data(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
# 测试异步函数
@pytest.mark.asyncio
async def test_fetch_data():
with patch('aiohttp.ClientSession.get') as mock_get:
# 创建异步mock
mock_context = AsyncMock()
mock_get.return_value = mock_context
mock_response = AsyncMock()
mock_response.json = AsyncMock(return_value={'data': 'test'})
mock_context.__aenter__.return_value = mock_response
result = await fetch_data('https://api.example.com/data')
assert result['data'] == 'test'
最佳实践建议
使用配置驱动的Mock
# mock_config.py
MOCK_RESPONSES = {
'GET': {
'https://api.example.com/users/1': {
'status': 200,
'json': {'id': 1, 'name': 'John'}
},
'https://api.example.com/users/2': {
'status': 404,
'json': {'error': 'User not found'}
}
},
'POST': {
'https://api.example.com/users': {
'status': 201,
'json': {'id': 3, 'name': 'New User'}
}
}
}
# test.py
import requests
from unittest.mock import patch
def mock_api_call(method, url, **kwargs):
"""通用API mock函数"""
config = MOCK_RESPONSES.get(method, {}).get(url, {})
response = Mock()
response.status_code = config.get('status', 200)
response.json.return_value = config.get('json', {})
return response
# 使用
with patch('requests.get', side_effect=mock_api_call):
result = requests.get('https://api.example.com/users/1')
print(result.json()) # {'id': 1, 'name': 'John'}
选择建议
- 简单测试:使用
unittest.mock.patch - 复杂API:使用
responses或requests-mock - 异步API:使用
AsyncMock - 开发环境:考虑用
VCR.py录制真实响应
Mock的关键是只模拟外部依赖,保持内部逻辑的真实性,这样测试才会真正验证代码的正确性。