Reputation: 1390
I'm using python responses
module to mock API response in my tests. The problem is that after the url is registered responses.add()
it can be called only once with requests.get()
, subsequent calls for the same URL raise an exception.
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")
Now the first call works:
>>> print(get_url(URL)) # <Response [200]>
However the same call again fails:
>>> 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:
>>>
Is there any way to make the mock URLs permanent and call them as many times as the tests need?
Upvotes: 2
Views: 8363
Reputation: 5793
The problem with your original code is that get_url
wrapped with decorator and it creates a new responses context every time when get_url
is called, but response.add
register url mock is registered only once - for the first response context.
@response.activate
decorator intended to be used for test cases.
Here is correct way of using decorator that allows to make requests to same 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()
Using responses.start() / responses.stop()
allows to make many requests for the same 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()
For unit tests I'm using this mixing code .
BTW Latest responses
version (0.12.0) has function assert_calls_count that allows to check the number of requests to url without exception.
assert responses.assert_call_count(URL, 1) is True
Upvotes: 4
Reputation: 2233
Short answer: no, I don't think so.
I am looking at the source code for responses
and one thing it does is raise an error for every uncalled request, so something like what you describe is incongruous with this kind of setup.
If I was facing this problem, I would make my own get
function that mocks the response in advance, like this:
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)
and I would use this instead of requests.get
.
Upvotes: 1