Open hynek opened 4 months ago
hi @hynek ,
I think you can achieve this by registering multiple oneshot requests. These are then pulled from the queue one by one:
import requests
from pytest_httpserver import HTTPServer
def test_multi_response(httpserver: HTTPServer):
httpserver.expect_oneshot_request("/foo").respond_with_data("FIRST")
httpserver.expect_oneshot_request("/foo").respond_with_data("SECOND")
assert requests.get(httpserver.url_for("/foo")).text == "FIRST"
assert requests.get(httpserver.url_for("/foo")).text == "SECOND"
The 3rd request for this URL would result in 500, but you can register a fallback method by a "normal" permanent handler:
import requests
from pytest_httpserver import HTTPServer
def test_multi_response(httpserver: HTTPServer):
httpserver.expect_oneshot_request("/foo").respond_with_data("FIRST")
httpserver.expect_oneshot_request("/foo").respond_with_data("SECOND")
httpserver.expect_request("/foo").respond_with_data("FALLBACK")
assert requests.get(httpserver.url_for("/foo")).text == "FIRST"
assert requests.get(httpserver.url_for("/foo")).text == "SECOND"
assert requests.get(httpserver.url_for("/foo")).text == "FALLBACK"
assert requests.get(httpserver.url_for("/foo")).text == "FALLBACK"
Hope this helps.
Tbh your attrs example looks great also :)
Zsolt
Hi @hynek ,
Just a friendly ping, have you seen my last comment? Did the way I suggested work for you?
Zsolt
Hi sorry for the delay, I'm traveling, I haven't quite made up my mind about it, but I've also not tried it, because it feels a bit repetitive.
What I think would be really cool it being about to write: httpserver.expect_oneshot_request("/foo").respond_with_data("FIRST").respond_with_data("FIRST")
🤔
But I think I like mine good enough – for those who want to copy paste, my latest version look like this which is a bit more user-friendly:
class MultipleResponsesHandler:
"""
A pytest-httpserver handler that returns different responses to subsequent
requests.
"""
_responses_left: list[Response]
def __init__(self, responses: Sequence[Response | str | bytes]):
self._responses_left = [
resp if isinstance(resp, Response) else Response(resp)
for resp in responses
]
def __call__(self, _: Request) -> Response:
return self._responses_left.pop(0)
I'm considering to add request-recording tho, since sometimes httpserver is a bit opaque about what went wrong and I could just accept everything and introspect. 🤔
hi @hynek ,
I looked at the current code of pytest-httpserver and implementing this fluent api you descibed would be a big refactoring. Not impossible but the code was written to have strictly one expectation for the request and one response.
However the problem you descibed seems to be valid indeed.
What I could imagine as a compromise between the fluent and the one I suggested (I agree it had code repetitions), is something like this:
httpserver.expect_request("/").respond_multiple([
Response(...),
Response(...),
])
It would accept an Iterable[Response]
so if someone wanted an infinite loop it can be implemented as well (with itertools.cycle or such).
So this would remove the ugly code repetition from my example and also it won't require huge refactorings in the code as well. This is just an idea, I don't want to push anything.
I'm interested in your final code. I'm also interested how you implement the request recording you mentioned.
Hi, thanks for the great project! There's one thing that keeps tripping me up and that's when I want to return multiple responses after each request. For example, to exercise retries.
Currently I'm using the following pattern:
Which can be generalized to:
Is there a more elegant way to achieve this and/or should this be part of pytest-httpserver?