问题
I've written a simple HTTP client using aiohttp and I'm trying to test it by patching aiohttp.ClientSession
and aiohttp.ClientResponse
. However, it appears as though the unittest.mock.patch
decorator is not respecting my asynchronous code. At a guess, I would say it's some kind of namespacing mismatch.
Here's a minimal example:
from aiohttp import ClientSession
async def is_ok(url:str) -> bool:
async with ClientSession() as session:
async with session.request("GET", url) as response:
return (response.status == 200)
I'm using an asynchronous decorator for testing, as described in this answer. So here's my attempted test:
import unittest
from unittest.mock import MagicMock, patch
from aiohttp import ClientResponse
from my.original.module import is_ok
class TestClient(unittest.TestCase):
@async_test
@patch("my.original.module.ClientSession", spec=True)
async def test_client(self, mock_client):
mock_response = MagicMock(spec=ClientResponse)
mock_response.status = 200
async def _mock_request(*args, **kwargs):
return mock_response
mock_client.request = mock_response
status = await is_ok("foo")
self.assertTrue(status)
My is_ok
coroutine works fine when it's used in, say, __main__
, but when I run the test, it gives me an error that indicates that the session.request
function has not been mocked per my patch
call. (Specifically it says "Could not parse hostname from URL 'foo'", which it should if it weren't mocked.)
I am unable to escape this behaviour. I have tried:
- Importing
is_ok
after the mocking is done. - Various combinations of assigning mocks to
mock_client
andmock_client.__aenter__
, settingmock_client.request
toMagicMock(return_value=mock_response)
, or usingmock_client().request
, etc. - Writing a mock
ClientSession
with specific__aenter__
and__aexit__
methods and using it in thenew
argument topatch
.
None of these appear to make a difference. If I put assertions into is_ok
to test that ClientSession
is an instance of MagicMock
, then these assertions fail when I run the test (as, again, they would when the code is not patched). That leads me to my namespacing mismatch theory: That is, the event loop is running in a different namespace to which patch
is targeting.
Either that, or I'm doing something stupid!
回答1:
Mocking ClientSession
is discouraged.
Recommended way is creation fake server and sending real requests to it.
Take a look on aiohttp example.
来源:https://stackoverflow.com/questions/46450545/testing-aiohttp-client-with-unittest-mock-patch