Closed adamdougal closed 4 months ago
I've got this implementation that I'm using in my tests as an example implementation:
import logging
from pytest_httpserver import HTTPServer
class RequestMatcher:
path: str
method: str
json: dict
headers: dict
query_string: dict
times: int
def __init__(self, path: str, method: str, json: dict = None, headers: dict = None, query_string: str = None, times: int = 1):
self.path = path
self.method = method
self.json = json
self.headers = headers
self.query_string = query_string
self.times = times
def __str__(self):
return f"Path: {self.path}, Method: {self.method}, JSON: {self.json}, Headers: {self.headers}, Query String: {self.query_string}, Times: {self.times}"
def verify_request_made(mock_httpserver: HTTPServer, request_matcher: RequestMatcher):
requests_log = mock_httpserver.log
similar_requests = []
matching_requests = []
for request_log in requests_log:
request = request_log[0]
if request.path == request_matcher.path:
similar_requests.append(request)
if request.method != request_matcher.method:
continue
if (request_matcher.json is not None and request.json != request_matcher.json):
continue
if (request_matcher.headers is not None):
for key, value in request_matcher.headers.items():
if request.headers.get(key) != value:
continue
if (request_matcher.query_string is not None and request.query_string.decode("utf-8") != request_matcher.query_string):
continue
error_message = f"Matching request found {len(matching_requests)} times but expected {request_matcher.times} times. \n Expected request: {request_matcher}\n Found similar requests:"
if len(matching_requests) != request_matcher.times:
for request in similar_requests:
error_message += "\n--- Similar Request Start"
error_message += f"\nPath: {request.path}, Method: {request.method}, Body: {request.get_data()}, Headers: {request.headers} Query String: {request.query_string.decode('utf-8')}"
error_message += "\n--- Similar Request End"
assert len(matching_requests) == request_matcher.times, error_message
I've not spent any time refactoring this code though so it could definitely be improved!
hi @adamdougal ,
Thanks for this! I think this would be a valuable addition to pytest-httpserver, I'll try to create a PR on the weekend for this. Also thanks for the example code, I think it helps a lot.
Zsolt
@adamdougal Added the POC for this, could you take a look at #294 ?
I thought we could re-use the existing matchers and run a match on them. This would nicely re-use the existing matching logic. Also, httpserver's create_matcher
method can be used to create a matcher object (or it can be created by the constructor as well).
What do you think?
I'm thinking about making some useful message for the assert
but I have no idea at the moment so I left it without any assertion message.
Heya! Makes complete sense to reuse what's there.
Re the error message, you can see what I did around similar requests above, which really aids debugging failures. But obviously that would required some changes to the current matching code, I guess to achieve the same you could do an initial match just on path?
I've had a look at the PR and it all looks great! Thanks for getting this raised so quickly!
Ah, I totally missed that similar requests logic in your code :facepalm:
...which is actually a very good idea, so I added those to the PR. Thanks! :+1:
See the error message in the tests.
What do you think? Should we change the error msg in some way?
Zsolt
This looks perfect to me!
Thanks for getting this implemented so quickly!
hi @adamdougal ,
Thanks!
I'm thinking about making a release but probably together with #290, but that will take a few days given my limited free time.
What do you think?
Or, if you prefer, I can publish a release with only this feature.
Zsolt
Heya, no rush from my side. We have the solution I referenced above in place so we're good for now. Thanks!
Heya!
Following on from my previous issue inspired by WireMock, another feature that I've always found useful is being able to verify the calls that have been made to the mock server. There are two main reasons why I think this is useful:
I think this could be implemented by introducing a new
RequestMatcher
object, for example:Wiremock docs for reference: https://wiremock.org/docs/verifying/
Again, happy to contibute where I have time if you're happy with this proposal.
Thanks!