0

I have the following code in the implementation (uses requests lib):

def call_service(product_ids: Set[str])
   response = requests.post(
      json={"product_ids": product_ids},
      url="http://whatever.com",
   )

   if response.status_code == 421:
      raise MisRedirectedRequest()

I'm using HTTPretty's to simulate this in a test:

@httpretty.activate
def test_http_status_code_421():
    httpretty.register_uri(
        method=httpretty.POST,
        uri="http://whatever.com",
        body="{}",
        status=421,
    )

   with pytest.raises(MisRedirectedRequest):
      call_service({"123", "543"})

However, MisRedirectedRequest is never raised. The test doesn't pass. By debugging, I get this in the implementation:

requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

The weird thing is that I tried with other HTTP error codes and it works fine (e.g. 420, 500).

Luís Soares
  • 5,726
  • 4
  • 39
  • 66
  • 1
    Your body (and http headers) aren't the same between both code blocks – OneCricketeer Sep 07 '22 at 22:35
  • but the body above (impl. code) is the *request* post body; the body below (test code) is the stubbed *response* body.. so it's normal they don't match. – Luís Soares Sep 07 '22 at 22:57
  • (and it works if I swap from 421 to 420 in both places) – Luís Soares Sep 07 '22 at 22:58
  • Okay, well, we don't know what your server is supposed to return, so keeping the actual HTTP request the same would make sense. Looks like you are actually making a request, not mocking one. Specifically, `call_service` would need to accept the URI argument from `httpretty.register_uri`, I believe, and not set its own (which could easily be different) – OneCricketeer Sep 07 '22 at 23:32
  • But since Python allows monkey patching, HTTPretty's can match whatever URL - capturing that call as well. In real life that would be another URL but it would still be the same in tests and implementation. I've done that in everywhere so far and it works. Except here. – Luís Soares Sep 08 '22 at 00:06
  • 1
    It works similarly to Java's WireMock. In both, the implementation thinks it's doing a real call. In Python you don't even need to inject a fake/localhost URL due to the monkey patching being more clever. – Luís Soares Sep 08 '22 at 00:08
  • httpretty.register_uri prepares a mock. Then it's supposed to be matched and consumed. – Luís Soares Sep 08 '22 at 00:09
  • Interesting. So, what happens when you remove `body="{}"`? – OneCricketeer Sep 08 '22 at 00:12
  • HTTPretty's puts in some dummy default, which is irrelevant here because it's not being used in the implementation code. Only the status code is being used in that if. – Luís Soares Sep 08 '22 at 00:20
  • 1
    it was a limitation in HTTPretty's: https://github.com/gabrielfalcao/HTTPretty/pull/458 – Luís Soares Sep 08 '22 at 09:15
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/247895/discussion-between-luis-soares-and-onecricketeer). – Luís Soares Sep 08 '22 at 22:13

1 Answers1

1

After hours of debugging, I discovered that HTTPretty did not support 421. I created a PR but meanwhile, this is the workaround:

from httpretty.http import STATUSES

STATUSES[421] = "Misdirected Request"

Update: PR is merged.

Luís Soares
  • 5,726
  • 4
  • 39
  • 66