0

我正在创建自己的夹具来模拟单元测试中所需的服务端点。为了拦截 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 仍在尝试解析主机?

4

2 回答 2

0

我已经解决了这个问题,这是由于底层代码(SPARQLWrapper)没有使用requests,而是urlopen直接使用,从而绕过了我的模拟。为了能够拦截这两种类型的访问,我使用了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)

当我注入夹具时,我必须进行额外的调用才能实际创建它:

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)
于 2021-10-06T12:10:40.233 回答
0

看来你没有在任何地方开始嘲笑?我对 pytest 没有太多经验,但是请求通过 urllib 的事实意味着它从未命中模拟对象。

你有一个可以运行的独立示例吗?我猜这与您产生 requests_mock 对象的方式有关。mocker 将像普通的上下文管理器一样工作,因此会在您退出范围时停止,但如果不跟踪它就很难说。

于 2021-10-05T06:57:00.423 回答