Reputation: 762
I'm currently trying to do unit tests using the requests_mock library in order to patch requests. I've written the following code:
def test_general_search(requests_mock):
params = {'query': 'testsetset', 'exact': 0, 'max_pages': '1', 'category': 'username'}
requests_mock.get(f'{MOCK_ADDRESS}', json=MOCK_RESPONSE)
client = Client(MOCK_ADDRESS, auth=MOCK_CREDS, headers=MOCK_HEADERS)
res = general_search(client, params)
assert ...
But I am getting the following error:
requests_mock.exceptions.NoMockAddress: No mock address: GET https://fake-url.com/search?query=username%3Atestsetset&page=1
Can anyone help me out with figuring out how to solve it? I've used mock as a pytest feature.
Upvotes: 20
Views: 17383
Reputation: 230
I have faced this issue recenlt. I'm not sure of the reason. Maybe this can help someone.
MOCK_SERVER_URL = "http://localhost:12345/"
def test_http_with_requests_mock(requests_mock):
HTML_RESPONSE = "<html><body><h1>Some error!</h1></body></html>"
requests_mock.get(MOCK_SERVER_URL + "/endpoint", text=HTML_RESPONSE)
[...]
def test_http_with_requests_mock(requests_mock):
HTML_RESPONSE = "<html><body><h1>Some error!</h1></body></html>"
requests_mock.get("http://localhost:12345/endpoint", text=HTML_RESPONSE)
[...]
Upvotes: 1
Reputation: 1027
I would recommend using a custom matcher that performs a match on the request's URL not including the querystring.
The documentation isn't very clear on how to go about this, but after breaking my head for a while I was able to put together this article explaining how custom matchers for requests_mock
work.
A custom matcher simply returns whether the request matched or not, for your use case you can even configure a single matcher to check for different URLs, or partial URLs, based on the URL in the request being matched.
The sample I created will hopefully make it clear enough for your use case:
from http import HTTPStatus
from urllib.parse import urlparse
import requests
import requests_mock
def a_matcher(request):
# will match the base url with any query string
parts = urlparse(request.url)
base_url = parts.scheme + "://" + parts.netloc + parts.path
if base_url == "http://www.example.com/path/to/the/magic":
return True
return None
def b_matcher(request):
# will only match exactly
if request.url == "http://www.example.com/road/to/hell":
return True
return None
def test_calls_made_out_of_order():
status_code_a = int(HTTPStatus.OK)
status_code_b = int(HTTPStatus.UNPROCESSABLE_ENTITY)
with requests_mock.Mocker() as mocker:
mocker.post(
requests_mock.ANY,
additional_matcher=a_matcher,
status_code=status_code_a,
)
mocker.post(
requests_mock.ANY,
additional_matcher=b_matcher,
status_code=status_code_b,
)
response_b = requests.post(
"http://www.example.com/road/to/hell",
headers={
"Accept": "application/json",
},
json={
"data": {
"b": True,
}
},
)
assert response_b.status_code == status_code_b
response_a = requests.post(
"http://www.example.com/path/to/the/magic?foo=bar",
headers={
"Accept": "application/json",
},
json={
"data": {
"a": True,
}
},
)
assert response_a.status_code == status_code_a
Upvotes: 1
Reputation: 1604
This occurs when something about the mock request
in this case
requests_mock.get(f'{MOCK_ADDRESS}', json=MOCK_RESPONSE)
does not match exactly the get request of the code being tested. So I'd say you need to print out both the URL in the test class and the one in the tested code.
For example, I was getting the same error, until I did something like
@requests_mock.Mocker(kw='mock')
def test_get_data_from_endpoints(self, **kwargs):
kwargs['mock'].get('http://testurl.org', json=response_1)
More info here: https://requests-mock.readthedocs.io/en/latest/matching.html#query-strings
Upvotes: 12