Python/Django/DRF/Pytest中如何实现Laravel Http::fake()功能?
在Django测试中模拟全局HTTP请求(替代Laravel的Http::fake())
为什么requests_mock达不到预期?
requests_mock默认只作用于测试函数的局部上下文,如果你在**应用内部代码(比如视图、服务类、模型方法)**里发起HTTP请求,它不会拦截这些请求,因为它们不在测试函数的mock作用域内。
实现全局HTTP请求模拟的两种方案
方案1:用requests_mock挂载全局适配器
把mock适配器绑定到requests的全局会话上,就能拦截所有位置发起的requests请求:
from django.test import TestCase import requests import requests_mock class ExternalAPITest(TestCase): def setUp(self): # 创建全局mock适配器 self.mock_adapter = requests_mock.Adapter() # 挂载到requests的默认会话,支持http和https协议 requests.Session.mount('http://', self.mock_adapter) requests.Session.mount('https://', self.mock_adapter) def test_mocked_third_party_request(self): # 配置mock规则:匹配指定请求地址和方法,返回模拟响应 self.mock_adapter.register_uri( 'GET', 'https://third-party-api.com/user-info', json={'id': 1, 'name': 'Mocked User'}, status_code=200 ) # 调用依赖第三方API的DRF接口 response = self.client.get('/api/user-profile/') # 断言接口返回的第三方数据符合模拟结果 self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['user_name'], 'Mocked User')
方案2:用responses库(更简洁的全局拦截)
responses库默认全局拦截所有requests请求,用装饰器即可快速启用:
import responses from django.test import TestCase class ExternalAPITest(TestCase): @responses.activate def test_simplified_mock(self): # 添加mock规则 responses.add( responses.POST, 'https://third-party-api.com/submit', json={'status': 'success'}, status=201 ) # 调用内部发起POST请求的接口 response = self.client.post('/api/submit-data/', {'content': 'test'}, format='json') self.assertEqual(response.json()['external_status'], 'success')
针对DRF内部API调用的模拟
如果你的代码是调用项目内部的DRF API端点,不需要mock外部请求,直接用APIClient本身模拟即可:
def test_internal_api_dependency(self): # 先模拟内部API的响应 self.client.post('/api/internal-config/', {'max_limit': 10}, format='json') # 调用依赖该内部接口的视图 response = self.client.get('/api/limited-data/') # 断言返回结果符合内部配置的限制 self.assertEqual(len(response.json()['data']), 10)
注意事项
- 若使用异步HTTP库(如aiohttp),需用对应mock工具(如aioresponses),原理一致,都是全局拦截请求。
- 所有mock规则会在测试结束后自动重置,不会影响其他测试用例。
内容的提问来源于stack exchange,提问作者Kamaro
相关产品推荐
相关产品推荐

