Colin-b / pytest_httpx

pytest fixture to mock HTTPX
https://colin-b.github.io/pytest_httpx/
MIT License
344 stars 32 forks source link

Registration order matters when multiple responses match a request, can regex be a specific case? #102

Closed realsuayip closed 12 months ago

realsuayip commented 1 year ago

Take this example:

httpx_mock.add_response(
    url=re.compile(r"http://example.com/"),
    status_code=404,
)

httpx_mock.add_response(
    url="http://example.com/test/123",
    status_code=200,
)

In this case, my expected behavior is:

First, match the more specific URL, otherwise fallback to more general URL.

However, the code above ends up creating flaky tests; most of the time, it works, but sometimes it fails when it matches the regex first and not the specific case.

As far as I understand, this can be solved by defining specific matchers before the general ones. And that's fine.

I have two suggestions:

  1. Document this behavior and keep it as is.
  2. Raise some exception when two different matchers match the same thing.
Colin-b commented 1 year ago

Hello @realsuayip ,

This behavior is already documented.

Considering that the following requests are issued by your code:

  1. http://example.com/test/123
  2. http://example.com/test/123
  3. http://example.com/test/1
  4. http://example.com/test/123

With your example, this would mean the following responses:

  1. 404 (as it matches the regex and it is hasn't been sent yet)
  2. 200 (as it matches the url and it hasn't been sent yet, while the regex was already sent)
  3. 404 (as it only matches the regex)
  4. 200 (as it matches both url and regex and url was the latest registered)

Unless you expect the absolute URL to be issued only once, changing the order of registration would NOT fix this issue as this would mean the following responses:

  1. 200 (as it matches the url and it is hasn't been sent yet)
  2. 404 (as it matches the regex and it hasn't been sent yet, while the url was already sent)
  3. 404 (as it only matches the regex)
  4. 404 (as it matches both url and regex and regex was the latest registered)

To properly fix your issue, your regex should exclude the specific URL it shouldn't match.

To come back on your proposal: I understand that, in your use case, you provide only 2 response, one being an absolute match and the other being a regex. It is indeed easy to imagine that we could make a deterministic choice and always chose the absolute match. However this might not be the expected behavior for everyone, moreover we can imagine use case with more than one regex matching the same url. Making it even harder to know what is the expected behavior for the user.

In any case, I am always eager to enhance the documentation to avoid unexpected behavior. Do you have any proposal as to how this could be achieved?

Thanks again

realsuayip commented 12 months ago

It seems that I have missed the relevant part in documentation. Thanks for the clarification.