requests_mock作为pytest fixture拦截未设置请求报错问题求助
我来帮你理清这个问题——这其实不是bug,是requests-mock fixture的默认行为:它会拦截所有通过requests库发起的请求,哪怕你没给对应URL设置mock规则。下面分两种场景给你解决方案:
一、让特定URL绕过mock,走真实网络请求
如果你希望https://api-b.com/的请求不被拦截,直接走真实接口,可以通过以下两种方式实现:
方法1:给目标URL添加带real_http=True的mock规则
在测试代码里,给https://api-b.com/添加一个允许真实请求的规则,这样requests-mock就会放行这个URL的所有请求:
def test_reqs(requests_mock): # Mock api-a的请求 requests_mock.get('https://api-a.com/') # 放行api-b的所有请求,走真实网络 requests_mock.get('https://api-b.com/', real_http=True) # 现在这个请求会走真实接口,不会被拦截报错 requests.get('https://api-b.com/') assert requests.get('https://api-a.com/')
如果api-b有多个路径,也可以用通配符匹配所有子路径:
requests_mock.get('https://api-b.com/*', real_http=True)
方法2:全局启用真实请求(不推荐,除非大部分请求都需要真实调用)
如果你的测试里大部分请求都需要走真实网络,只有少数需要mock,可以直接给requests-mock对象设置全局真实请求开关:
def test_reqs(requests_mock): requests_mock.real_http = True # 只mock需要拦截的api-a requests_mock.get('https://api-a.com/') requests.get('https://api-b.com/') # 走真实请求 assert requests.get('https://api-a.com/')
二、解决第三方模块内部调用被拦截的问题
第三方模块内部用requests发起的请求也会被requests-mock拦截,这是因为requests-mock是通过patchrequests.Session.send实现全局拦截的。解决思路有两种:
思路1:给第三方模块调用的URL放行(推荐)
和上面的方法一样,只要知道第三方模块调用的目标URL,给它添加real_http=True的规则即可:
def test_third_party(requests_mock): # Mock你的业务接口依赖的api-a requests_mock.get('https://api-a.com/') # 放行第三方模块调用的api-b requests_mock.get('https://api-b.com/', real_http=True) # 调用第三方模块的方法,它内部的api-b请求会走真实网络 third_party_module.some_function()
思路2:绕过requests-mock,直接mock第三方模块的方法
如果不想依赖requests-mock的URL规则,可以用pytest-mock直接mock第三方模块的具体方法,而不是mockrequests本身。比如第三方模块third_party里有个call_api方法内部调用了requests.get('https://api-b.com/'),你可以直接mock这个call_api方法:
def test_third_party(mocker): # Mock第三方模块的方法,返回你需要的模拟结果 mocker.patch('third_party.call_api', return_value={'data': 'fake_response'}) # 同时用requests-mock上下文管理器mock你的api-a from requests_mock import Mocker with Mocker() as m: m.get('https://api-a.com/') # 执行你的业务逻辑测试 your_service.process_data()
这种方法的好处是完全隔离第三方模块的请求,不需要关心它内部用了哪个URL,但前提是你能明确第三方模块的调用入口。
总结一下
requests-mock的全局拦截是设计如此,不是bug。你只需要通过real_http=True规则放行不需要mock的URL,或者针对第三方模块的方法直接mock,就能解决问题。
内容的提问来源于stack exchange,提问作者Leonid Ivanov

