Anu*_*ara 5 python asynchronous mocking pytest httpx
我需要为一个用于从 API 获取数据的函数编写测试用例。在那里我使用 httpx.AsyncClient() 作为上下文管理器。但我不明白如何为该功能编写测试用例。
async def make_dropbox_request(url, payload, dropbox_token):
async with httpx.AsyncClient(timeout=None, follow_redirects=True) as client:
headers = {
'Content-Type': 'application/json',
'authorization': 'Bearer '+ dropbox_token
}
# make the api call
response = await client.post(url, headers=headers, json=payload)
if response.status_code not in [200]:
print('Dropbox Status Code: ' + str(response.status_code))
if response.status_code in [200, 202, 303]:
return json.loads(response.text)
elif response.status_code == 401:
raise DropboxAuthenticationError()
elif response.status_code == 429:
sleep_time = int(response.headers['Retry-After'])
if sleep_time < 1*60:
await asyncio.sleep(sleep_time)
raise DropboxMaxRateLimitError()
raise DropboxMaxDailyRateLimitError()
raise DropboxHTTPError()
Run Code Online (Sandbox Code Playgroud)
我需要在不调用 API 的情况下编写测试用例。所以我相信在这种情况下我需要模拟client.post()但我不明白如何做到这一点。如果有人能帮助我解决这个问题,那对我来说真的很有帮助。
我也遇到了同样的问题并用patch装饰器处理了它。我分享我的代码,这样可能对其他人有帮助。
from unittest.mock import patch
import pytest
import httpx
from app.services import your_service
@pytest.mark.anyio
@patch(
'app.services.your_service.httpx.AsyncClient.post',
return_value = httpx.Response(200, json={'id': '9ed7dasdasd-08ff-4ae1-8952-37e3a323eb08'})
)
async def test_get_id(mocker):
result = await your_service.get_id()
assert result == '9ed7dasdasd-08ff-4ae1-8952-37e3a323eb08'
Run Code Online (Sandbox Code Playgroud)
TL;DR:用于return_value.__aenter__.return_value模拟异步上下文。
假设您正在使用Pytest和pytest-mock,您可以使用该mocker装置来模拟httpx.AsyncClient。
由于该post函数是异步的,因此您需要使用AsyncMock. 最后,由于您使用异步上下文,因此您还需要使用它return_value.__aenter__.return_value来正确模拟返回的上下文。请注意,对于同步上下文,只需使用__enter__而不是__aenter__.
@pytest.fixture
def mock_AsyncClient(mocker: MockerFixture) -> Mock:
mocked_AsyncClient = mocker.patch(f"{TESTED_MODULE}.AsyncClient")
mocked_async_client = Mock()
response = Response(status_code=200)
mocked_async_client.post = AsyncMock(return_value=response)
mocked_AsyncClient.return_value.__aenter__.return_value = mocked_async_client
return mocked_async_client
Run Code Online (Sandbox Code Playgroud)