-
-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Calls info in BaseResponse #664
Changes from 8 commits
3f7660a
77ca597
0d29ad1
5669688
34d825f
7f7085e
0e515ff
d78499d
48f9615
aa29301
d1b0650
f6a7dd3
9f5e733
654c607
41bb479
51f4e56
ea1144d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1079,6 +1079,75 @@ Assert that the request was called exactly n times. | |
responses.assert_call_count("http://www.example.com?hello=world", 1) is True | ||
|
||
|
||
Assert Request Calls data | ||
------------------ | ||
|
||
``Request`` object has ``calls`` list which elements correspond to ``Call`` objects | ||
in the global list of ``Registry``. This can be useful when the order of requests is not | ||
guaranteed, but you need to check their correctness, for example in multithreaded | ||
applications. | ||
|
||
.. code-block:: python | ||
|
||
import concurrent.futures | ||
import responses | ||
import requests | ||
|
||
|
||
@responses.activate | ||
def test_assert_calls_on_resp(): | ||
uid_with_permissions = [ | ||
("0123", {"client": True, "admin": False, "disabled": False}), | ||
("1234", {"client": False, "admin": True, "disabled": False}), | ||
("2345", {"client": False, "admin": False, "disabled": True}), | ||
] | ||
rsp0123 = responses.patch( | ||
"http://www.foo.bar/0123/", | ||
json={"OK": True, "uid": "0123"}, | ||
status=200, | ||
) | ||
rsp1234 = responses.patch( | ||
"http://www.foo.bar/1234/", | ||
json={"OK": False, "uid": "1234"}, | ||
status=400, | ||
) | ||
rsp2345 = responses.patch( | ||
"http://www.foo.bar/2345/", | ||
json={"OK": True, "uid": "2345"}, | ||
status=200, | ||
) | ||
|
||
def update_permissions(uid, permissions): | ||
url = f"http://www.foo.bar/{uid}/" | ||
response = requests.patch(url, json=permissions) | ||
return response | ||
|
||
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: | ||
future_to_uid = { | ||
executor.submit(update_permissions, uid, permissions): uid | ||
for (uid, permissions) in uid_with_permissions | ||
} | ||
for future in concurrent.futures.as_completed(future_to_uid): | ||
uid = future_to_uid[future] | ||
response = future.result() | ||
print("%s updated with %d status code" % (uid, response.status_code)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please update it with f-string There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
assert len(responses.calls) == 3 # total calls count | ||
|
||
assert rsp0123.call_count == 1 | ||
assert rsp0123.calls[0] in responses.calls | ||
assert json.loads(rsp0123.calls[0].request.body) == {"client": True, "admin": False, "disabled": False} | ||
|
||
assert rsp1234.call_count == 1 | ||
assert rsp1234.calls[0] in responses.calls | ||
assert json.loads(rsp1234.calls[0].request.body) == {"client": False, "admin": True, "disabled": False} | ||
assert rsp1234.calls[0].response.json() == {"OK": False, "uid": "1234"} | ||
|
||
assert rsp2345.call_count == 1 | ||
assert rsp2345.calls[0] in responses.calls | ||
assert json.loads(rsp2345.calls[0].request.body) == {"client": False, "admin": False, "disabled": True} | ||
|
||
|
||
Multiple Responses | ||
------------------ | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,4 +1,5 @@ | ||||||||||||||||||||||||||
import inspect | ||||||||||||||||||||||||||
import json | ||||||||||||||||||||||||||
import os | ||||||||||||||||||||||||||
import re | ||||||||||||||||||||||||||
import warnings | ||||||||||||||||||||||||||
|
@@ -1986,6 +1987,88 @@ def run(): | |||||||||||||||||||||||||
assert_reset() | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
def test_response_and_requests_mock_calls_are_equal(): | ||||||||||||||||||||||||||
@responses.activate | ||||||||||||||||||||||||||
def run(): | ||||||||||||||||||||||||||
rsp = responses.add(responses.GET, "http://www.example.com") | ||||||||||||||||||||||||||
rsp2 = responses.add(responses.GET, "http://www.example.com/1") | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
requests.get("http://www.example.com") | ||||||||||||||||||||||||||
requests.get("http://www.example.com/1") | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
assert len(responses.calls) == 2 | ||||||||||||||||||||||||||
assert rsp.call_count == 1 | ||||||||||||||||||||||||||
assert rsp.calls[0] is responses.calls[0] | ||||||||||||||||||||||||||
assert rsp2.call_count == 1 | ||||||||||||||||||||||||||
assert rsp2.calls[0] is responses.calls[1] | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
run() | ||||||||||||||||||||||||||
assert_reset() | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
def test_response_call_request(): | ||||||||||||||||||||||||||
@responses.activate | ||||||||||||||||||||||||||
def run(): | ||||||||||||||||||||||||||
rsp = responses.add(responses.GET, "http://www.example.com") | ||||||||||||||||||||||||||
rsp2 = responses.add( | ||||||||||||||||||||||||||
responses.PUT, "http://www.foo.bar/42/", json={"id": 42, "name": "Bazz"} | ||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
requests.get("http://www.example.com") | ||||||||||||||||||||||||||
requests.get("http://www.example.com?hello=world") | ||||||||||||||||||||||||||
requests.put( | ||||||||||||||||||||||||||
"http://www.foo.bar/42/", | ||||||||||||||||||||||||||
json={"name": "Bazz"}, | ||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
assert rsp.call_count == 2 | ||||||||||||||||||||||||||
request = rsp.calls[0].request | ||||||||||||||||||||||||||
assert request.url == "http://www.example.com/" | ||||||||||||||||||||||||||
assert request.method == "GET" | ||||||||||||||||||||||||||
request = rsp.calls[1].request | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can make it a bit more readable by enumerating
Suggested change
and so on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make sense. Made tests readable. Please take a look |
||||||||||||||||||||||||||
assert request.url == "http://www.example.com/?hello=world" | ||||||||||||||||||||||||||
assert request.method == "GET" | ||||||||||||||||||||||||||
assert rsp2.call_count == 1 | ||||||||||||||||||||||||||
request = rsp2.calls[0].request | ||||||||||||||||||||||||||
assert request.url == "http://www.foo.bar/42/" | ||||||||||||||||||||||||||
assert request.method == "PUT" | ||||||||||||||||||||||||||
request_payload = json.loads(request.body) | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what exactly do we test here ? why do we need to test that request body could be converted? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I changed the test a little) Here we validate that request
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
correct, but do we need to check it at all as part of we attach responses/responses/__init__.py Line 1041 in 5c6a3b1
and in the case of this PR we can skip this check since it does not add a value. although, you can fire a parallel PR that can add a separate test to validate that we have all the required data is attached to a request There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You are right, I missed this moment. So, in other words, in the current PR it is enough to test that calls of local mocks are identical to calls of the global list without deep validation of def test_response_calls_and_registry_calls_are_equal():
@responses.activate
def run():
rsp1 = responses.add(responses.GET, "http://www.example.com")
rsp2 = responses.add(responses.GET, "http://www.example.com/1")
requests.get("http://www.example.com")
requests.get("http://www.example.com/1")
requests.get("http://www.example.com")
assert len(responses.calls) == len(rsp1.calls) + len(rsp2.calls)
assert rsp1.call_count == 2
assert len(rsp1.calls) == 2
assert rsp1.calls[0] is responses.calls[0]
assert rsp1.calls[1] is responses.calls[2]
assert rsp2.call_count == 1
assert len(rsp2.calls) == 1
assert rsp2.calls[0] is responses.calls[1]
run()
assert_reset() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @beliaev-maksim and what about this question? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zeezdev sorry, missed this one in a long thread. Yes. |
||||||||||||||||||||||||||
assert request_payload == {"name": "Bazz"} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
run() | ||||||||||||||||||||||||||
assert_reset() | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
def test_response_call_response(): | ||||||||||||||||||||||||||
@responses.activate | ||||||||||||||||||||||||||
def run(): | ||||||||||||||||||||||||||
rsp = responses.add(responses.GET, "http://www.example.com", body=b"test") | ||||||||||||||||||||||||||
rsp2 = responses.add( | ||||||||||||||||||||||||||
responses.POST, | ||||||||||||||||||||||||||
"http://www.foo.bar/42/", | ||||||||||||||||||||||||||
json={"id": 42, "name": "Bazz"}, | ||||||||||||||||||||||||||
status=201, | ||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
requests.get("http://www.example.com") | ||||||||||||||||||||||||||
requests.post( | ||||||||||||||||||||||||||
"http://www.foo.bar/42/", | ||||||||||||||||||||||||||
json={"name": "Bazz"}, | ||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
assert rsp.call_count == 1 | ||||||||||||||||||||||||||
response = rsp.calls[0].response | ||||||||||||||||||||||||||
assert response.content == b"test" | ||||||||||||||||||||||||||
assert response.status_code == 200 | ||||||||||||||||||||||||||
assert rsp2.call_count == 1 | ||||||||||||||||||||||||||
response = rsp2.calls[0].response | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, could be enumerated. Something like
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree, done |
||||||||||||||||||||||||||
assert response.json() == {"id": 42, "name": "Bazz"} | ||||||||||||||||||||||||||
assert response.status_code == 201 | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
run() | ||||||||||||||||||||||||||
assert_reset() | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
def test_fail_request_error(): | ||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||
Validate that exception is raised if request URL/Method/kwargs don't match | ||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that this example might look very close to what you have in production. But can we unload it a bit and reduce complexity?
we probably still want to show an example of
concurrent
since this could be one of the main usages, but we do not need all those complicated matrices of settings to show the usagecan you please simplify it to remove additional arguments and have more clear names like
rsp1, rsp2, rsp3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got you, I'll try to simplify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simplified, please take a look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zeezdev now looks a way better, thank you!