0

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

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?

4

3 回答 3

0

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

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
于 2020-12-15T03:14:13.773 回答
0

就在这里。来自文档:“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]
于 2020-11-20T14:01:13.627 回答
0

是的,有办法!

您需要使用additional_matcher回调(请参阅文档)和requests_mock.ANYURL。

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

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' 
于 2021-11-10T17:42:16.353 回答