Python脚本Mock外部API如何做

wen 实用脚本 1

本文目录导读:

Python脚本Mock外部API如何做

  1. 使用 unittest.mock(标准库)
  2. 使用第三方库
  3. 高级Mock技巧
  4. 最佳实践建议
  5. 选择建议

在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'}

选择建议

  1. 简单测试:使用 unittest.mock.patch
  2. 复杂API:使用 responsesrequests-mock
  3. 异步API:使用 AsyncMock
  4. 开发环境:考虑用 VCR.py 录制真实响应

Mock的关键是只模拟外部依赖,保持内部逻辑的真实性,这样测试才会真正验证代码的正确性。

抱歉,评论功能暂时关闭!