【问题标题】:How to mock multiple urls in request mock如何在请求模拟中模拟多个网址
【发布时间】:2021-01-23 16:55:57
【问题描述】:

我有一个方法,它调用两个不同的端点并验证那里的响应。

def foo_bar:
  status_1 = requests.post(
        "http://myapi/test/status1", {},
        headers=headers)

  status_2 = requests.post(
        "http://myapi/test/status2", {},
        headers=headers)
  
 # and check the responses ...

我想像这样模拟 pytest 中的两个 url:

def foo_test:
   with requests_mock.Mocker() as m1:
       m1.post('http://myapi/test/status1',
               json={},
               headers={'x-api-key': my_api_key})
       
       m1.post('http://myapi/test/status2',
               json={},
               headers={'x-api-key': my_api_key})

它总是抛出错误

**NO mock address: http://myapi/test/status2**

似乎是它唯一的模拟第一个网址。

那么有没有办法在一种方法中模拟多个 url?

【问题讨论】:

    标签: python-3.x python-requests python-mock requests-mock


    【解决方案1】:

    是的,有。来自docs:“requests_mock.ANY 中有一个特殊符号,它充当通配符来匹配任何内容。它可以用作方法和/或 URL 的替换。”

    import requests_mock
    
    with requests_mock.Mocker() as rm:
        rm.post(requests_mock.ANY, text='resp')
    

    我不确定这是否是最好的方法,但它对我有用。您可以随后断言调用了哪些 URL:

    urls = [r._request.url, for r in rm._adapter.request_history]
    

    【讨论】:

      【解决方案2】:

      我认为您还有其他事情要做,一次模拟一个这样的路径是很正常的,这样您就可以简单地从不同的路径返回不同的值。你的例子对我有用:

      import requests
      import requests_mock
      
      with requests_mock.Mocker() as m1:
          my_api_key = 'key'
      
          m1.post('http://myapi/test/status1',
                  json={},
                  headers={'x-api-key': my_api_key})
      
          m1.post('http://myapi/test/status2',
                  json={},
                  headers={'x-api-key': my_api_key})
      
          headers = {'a': 'b'}
      
          status_1 = requests.post("http://myapi/test/status1", {}, headers=headers)
          status_2 = requests.post("http://myapi/test/status2", {}, headers=headers)
      
          assert status_1.status_code == 200
          assert status_2.status_code == 200
      

      【讨论】:

        【解决方案3】:

        是的,有办法!

        您需要使用additional_matcher 回调(参见docs)和requests_mock.ANY 作为URL。

        您的示例(使用上下文管理器)

        import requests
        import requests_mock
        
        
        headers = {'key': 'val', 'another': 'header'}
        
        
        def my_matcher(request):
            url = request.url
            mocked_urls = [
                "http://myapi/test/status1",
                "http://myapi/test/status2",
            ]
            return url in mocked_urls  # True or False
        
        # as Context manager
        with requests_mock.Mocker() as m1:
            m1.post(
                requests_mock.ANY,  # Mock any URL before matching
                additional_matcher=my_matcher,  # Mock only matched
                json={},
                headers=headers,
            )
            r = requests.post('http://myapi/test/status1')
            print(f"{r.text} | {r.headers}")
            r = requests.post('http://myapi/test/status2')
            print(f"{r.text} | {r.headers}")
        
            # r = requests.get('http://myapi/test/status3').text  # 'NoMockAddress' exception
        

        适配pytest

        注意: 使用别名导入 requests_mock(因为 requests_mock 是 pytest 测试中的夹具)
        请参阅 pytest 框架、GET 方法和您的 URL 的示例:

        # test_some_module.py
        import requests
        import requests_mock as req_mock
        
        
        def my_matcher(request):
            url = request.url
            mocked_urls = [
                "http://myapi/test/status1",
                "http://myapi/test/status2",
            ]
            return url in mocked_urls  # True or False
        
        
        def test_mocking_several_urls(requests_mock):  # 'requests_mock' is fixture here
            requests_mock.get(
                req_mock.ANY,  # Mock any URL before matching
                additional_matcher=my_matcher,  # Mock only matched
                text="Some fake response for all matched URLs",
            )
        
            ... Do your requests ...
            # GET URL#1 -> response "Some fake response for all matched URLs"
            # GET URL#2 -> response "Some fake response for all matched URLs"
            # GET URL#N -> Raised exception 'NoMockAddress' 
        

        【讨论】:

          猜你喜欢
          • 2019-05-06
          • 2021-03-27
          • 1970-01-01
          • 2019-08-07
          • 1970-01-01
          • 2020-04-04
          • 2018-10-02
          • 1970-01-01
          • 2018-03-16
          相关资源
          最近更新 更多