pnuckowski / aioresponses

Aioresponses is a helper for mock/fake web requests in python aiohttp package.
MIT License
513 stars 86 forks source link

aioresponses ignores custom response_class provided to aiohttp.ClientSession constructor #243

Open hf-kklein opened 1 year ago

hf-kklein commented 1 year ago

I'm using the following code, which preserves the response body in case raise_for_status=True. I copied it from https://github.com/aio-libs/aiohttp/issues/4600#issuecomment-922520737 and it works in reality but not when testing with aioresponses:

import aiohttp
import pytest
from aioresponses import aioresponses

class MyClientResponse(aiohttp.ClientResponse):
    async def start(self, connection: aiohttp.connector.Connection) -> aiohttp.ClientResponse:
        result = await super().start(connection)
        if self.status >= 400:
            await self.read()  # Avoid a ClientConnectionError later
        return result

    def raise_for_status(self) -> None:
        try:
            super().raise_for_status()
        except aiohttp.ClientResponseError as err:
            try:
                coro = self.text()
                try:
                    coro.send(None)
                except StopIteration as text:
                    if text.value:
                        err.message = text.value # <-- "Internal Server Error" is replaced with "terrible crash"
                finally:
                    coro.close()
            finally:
                raise err

class TestClientResponseClass:
    async def test_mock_bypasses_session_response_class(self):
        with pytest.raises(aiohttp.ClientResponseError) as excinfo:
            with aioresponses() as mocked:
                mocked.post("https://myserver.inv/", status=500, payload="terrible crash")
                session = aiohttp.ClientSession(raise_for_status=True, response_class=MyClientResponse)
                _ = await session.post("https://myserver.inv/", json={"foo": "bar"})
        assert isinstance(excinfo.value, aiohttp.ClientResponseError) #  ok
        assert excinfo.value.message == "terrible crash" #  fails!

I cannot point my finger on it. Might be my test setup is wrong but I feel like this is an error/missing feature of aioresponses, because, as I said, it works with a real server but not with a mocked one.

p2vvel commented 10 months ago

Had the same problem and resolved it by adding response_class like below:

with aioresponses() as mocked:
                mocked.post("https://myserver.inv/", status=500, payload="terrible crash", response_class=MyClientResponse)
hf-kklein commented 10 months ago

@p2vvel So you mean: Adding the response class to the actual request instead of to the session is a workaround, right?

p2vvel commented 10 months ago

Yes, I managed to use custom raise_for_status() during testing with aioresponses that way.