【问题标题】:Python "responses" mock - unable to call one URL multiple timesPython“响应”模拟 - 无法多次调用一个 URL
【发布时间】:2020-07-23 23:35:05
【问题描述】:

我正在使用 python responses 模块在我的测试中模拟 API 响应。问题是,在注册了 url responses.add() 之后,它只能用requests.get() 调用一次,随后对同一 URL 的调用会引发异常。

import requests
import responses

URL = 'http://localhost/abcd'

# Test method
@responses.activate
def get_url(url):
  return requests.get(url)

# Set up URL mock
responses.add(responses.GET, URL, body="A B C D")

现在第一个调用有效:

>>> print(get_url(URL))   # <Response [200]>

但是同样的调用再次失败:

>>> print(get_url(URL))

Traceback (most recent call last):
  File "test-responses.py", line 19, in <module>
    print(get_url(URL))
  File "<string>", line 3, in wrapper
  File "test-responses.py", line 10, in get_url
    return requests.get(url)
  File ".../site-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File ".../site-packages/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File ".../site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File ".../site-packages/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File ".../site-packages/responses.py", line 674, in unbound_on_send
    return self._on_request(adapter, request, *a, **kwargs)
  File ".../site-packages/responses.py", line 654, in _on_request
    raise response
requests.exceptions.ConnectionError: Connection refused by Responses - the call doesn't match any registered mock.

Request: 
- GET http://localhost/abcd

Available matches:

>>>

有什么方法可以使模拟 URL 永久化并根据测试需要多次调用它们?

【问题讨论】:

    标签: python unit-testing python-requests mocking


    【解决方案1】:

    简短回答:不,我不这么认为。 我正在查看responses 的源代码,它所做的一件事是为每个 未调用的请求引发错误,因此您所描述的内容与这种设置不符。

    如果我遇到这个问题,我会创建自己的 get 函数来提前模拟响应,如下所示:

    def mocked_get(url, body="A B C D", params=None, **kwargs):  # I stole the arguments from requests.get
        responses.add(responses.GET, url, body=body)
        return requests.get(url, params=params, **kwargs)
    

    我会用这个代替requests.get

    【讨论】:

      【解决方案2】:

      您的原始代码的问题是 get_url 用装饰器包装,并且每次调用 get_url 时它都会创建一个新的响应上下文,但 response.add 注册 url 模拟只注册一次 - 对于第一个响应上下文.

      @response.activate 用于测试用例的装饰器。 这是使用装饰器的正确方法,允许向相同的 url 发出请求。

      @responses.activate
      def test_function():
          responses.add(responses.GET, URL, body="A B C D")
          print(get_url(URL))
          print(get_url(URL))
      
      test_function()
      

      使用responses.start() / responses.stop() 允许对同一个 URL 发出多个请求。

      
      import requests
      import responses
      
      URL = 'http://localhost/abcd'
      
      def get_url(url):
          return requests.get(url)
      
      # Test method
      responses.start()
      # Set up URL mock
      responses.add(responses.GET, URL, body="A B C D")
      print(get_url(URL))
      print(get_url(URL))
      responses.stop()
      

      对于单元测试,我使用this 混合代码。

      顺便说一句,最新的responses 版本(0.12.0)具有assert_calls_count 功能,可以毫无例外地检查对 url 的请求数。

      assert responses.assert_call_count(URL, 1) is True
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-17
        • 1970-01-01
        • 2022-01-06
        • 2020-03-04
        • 2019-07-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多