在另一个夹具中使用 requests_mock 时,模拟的 URL 不会转发给处理程序
Mocked URLs not being forward to handler when using requests_mock in another fixture
我正在创建自己的装置来模拟我的单元测试中所需的服务端点。为了拦截 HTTP 请求,我使用 requests_mock 如下:
@pytest.fixture
def sparql_endpoint(requests_mock):
yield lambda uri, initial_data: Endpoint(requests_mock, uri, initial_data)
在 Endpoint.__init__
中,我执行以下操作:
m.post(url=uri, raw=self.handle_post)
m.get(url=uri, raw=self.handle_get)
在我的实际测试用例中,我注入端点并对其进行初始化:
def test_basic_select(my_endpoint):
repo_uri = 'https://my.rdfdb.com/repo/sparql'
rdf_files = ['tests/upper_ontology.ttl',
'tests/domain_ontology.ttl',
'tests/instance_data.ttl']
endpoint = sparql_endpoint(repo_uri, rdf_files)
实际上,它会初始化模拟端点,如果我在那里设置断点,我会看到 Mocker.start()
会被调用。但是,稍后在测试用例中我得到以下信息:
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:222: in urlopen
return opener.open(url, data, timeout)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:525: in open
response = self._open(req, data)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:543: in _open
'_open', req)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:503: in _call_chain
result = func(*args)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:1360: in https_open
context=self._context, check_hostname=self._check_hostname)
E urllib.error.URLError: <urlopen error [Errno 11001] getaddrinfo failed>
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:1319: URLError
因为无法解析我给的假的URL。那么,我是否以某种方式弄乱了处理程序注册,以便 Matcher 不会在那里踢请求?为什么 urlopen 仍在尝试解析主机?
看起来你没有在任何地方启动嘲笑者?我没有太多使用 pytest 的经验,但请求通过 urllib 的事实意味着它永远不会命中模拟对象。
您是否有一个可以 运行 的独立示例?我猜这与您生成 requests_mock 对象的方式有关。模拟器将像普通的上下文管理器一样工作,因此当您退出范围时会停止,但如果不跟踪它就很难说。
我已经解决了问题,这是由于底层代码(SPARQLWrapper) not using requests
, instead using urlopen
directly, and thus bypassing my mock. In order to be able to intercept both types of access, I resorted to using HTTPretty,它做了更彻底的模拟。代码最终如下所示:
首先,在灯具本身中,我启用了模拟:
httpretty.set_default_thread_timeout(60)
# enable HTTPretty so that it will monkey patch the socket module
httpretty.enable(verbose=True, allow_net_connect=False)
yield lambda uri, initial_data, **kwargs: Endpoint(uri, initial_data, **kwargs)
# disable afterwards, so that you will have no problems in code that uses that socket module
httpretty.disable()
# reset HTTPretty state (clean up registered urls and request history)
httpretty.reset()
请注意,我生成了一个 lambda
来创建实现夹具的实例,因此在清理之后,httpretty
也可以清理。
在夹具初始化中,我创建了绑定:
httpretty.register_uri(httpretty.GET, uri,
body=self.handle_get)
httpretty.register_uri(httpretty.POST, uri,
body=self.handle_post)
当我注入 fixture 时,我必须进行额外的调用才能实际创建它:
def test_request_get(sparql_endpoint):
repo_uri = 'https://my.rdfdb.com/repo/sparql'
rdf_files = ['tests/upper_ontology.ttl',
'tests/domain_ontology.ttl',
'tests/instance_data.ttl']
# This calls the lambda defined in the fixture
endpoint = sparql_endpoint(repo_uri, rdf_files)
我正在创建自己的装置来模拟我的单元测试中所需的服务端点。为了拦截 HTTP 请求,我使用 requests_mock 如下:
@pytest.fixture
def sparql_endpoint(requests_mock):
yield lambda uri, initial_data: Endpoint(requests_mock, uri, initial_data)
在 Endpoint.__init__
中,我执行以下操作:
m.post(url=uri, raw=self.handle_post)
m.get(url=uri, raw=self.handle_get)
在我的实际测试用例中,我注入端点并对其进行初始化:
def test_basic_select(my_endpoint):
repo_uri = 'https://my.rdfdb.com/repo/sparql'
rdf_files = ['tests/upper_ontology.ttl',
'tests/domain_ontology.ttl',
'tests/instance_data.ttl']
endpoint = sparql_endpoint(repo_uri, rdf_files)
实际上,它会初始化模拟端点,如果我在那里设置断点,我会看到 Mocker.start()
会被调用。但是,稍后在测试用例中我得到以下信息:
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:222: in urlopen
return opener.open(url, data, timeout)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:525: in open
response = self._open(req, data)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:543: in _open
'_open', req)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:503: in _call_chain
result = func(*args)
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:1360: in https_open
context=self._context, check_hostname=self._check_hostname)
E urllib.error.URLError: <urlopen error [Errno 11001] getaddrinfo failed>
..\..\AppData\Local\Programs\Python\Python37\lib\urllib\request.py:1319: URLError
因为无法解析我给的假的URL。那么,我是否以某种方式弄乱了处理程序注册,以便 Matcher 不会在那里踢请求?为什么 urlopen 仍在尝试解析主机?
看起来你没有在任何地方启动嘲笑者?我没有太多使用 pytest 的经验,但请求通过 urllib 的事实意味着它永远不会命中模拟对象。
您是否有一个可以 运行 的独立示例?我猜这与您生成 requests_mock 对象的方式有关。模拟器将像普通的上下文管理器一样工作,因此当您退出范围时会停止,但如果不跟踪它就很难说。
我已经解决了问题,这是由于底层代码(SPARQLWrapper) not using requests
, instead using urlopen
directly, and thus bypassing my mock. In order to be able to intercept both types of access, I resorted to using HTTPretty,它做了更彻底的模拟。代码最终如下所示:
首先,在灯具本身中,我启用了模拟:
httpretty.set_default_thread_timeout(60)
# enable HTTPretty so that it will monkey patch the socket module
httpretty.enable(verbose=True, allow_net_connect=False)
yield lambda uri, initial_data, **kwargs: Endpoint(uri, initial_data, **kwargs)
# disable afterwards, so that you will have no problems in code that uses that socket module
httpretty.disable()
# reset HTTPretty state (clean up registered urls and request history)
httpretty.reset()
请注意,我生成了一个 lambda
来创建实现夹具的实例,因此在清理之后,httpretty
也可以清理。
在夹具初始化中,我创建了绑定:
httpretty.register_uri(httpretty.GET, uri,
body=self.handle_get)
httpretty.register_uri(httpretty.POST, uri,
body=self.handle_post)
当我注入 fixture 时,我必须进行额外的调用才能实际创建它:
def test_request_get(sparql_endpoint):
repo_uri = 'https://my.rdfdb.com/repo/sparql'
rdf_files = ['tests/upper_ontology.ttl',
'tests/domain_ontology.ttl',
'tests/instance_data.ttl']
# This calls the lambda defined in the fixture
endpoint = sparql_endpoint(repo_uri, rdf_files)