Skip to main content

pytest-asyncio-httpx-mocking

When masking httpx.AsyncClient with unittest.mock in Pytest, AsyncMock must be used instead of MagicMock for async methods like post/get to prevent TypeError when awaited.

설치로 이동

소스 정보

저장소
Project-N-E-K-O/N.E.K.O
최근 소스 활동
2026년 3월 22일 07:07
감지된 SKILL.md 언어
중국어
스타
2,915
포크
321

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
pytest-asyncio-httpx-mocking
description
When masking httpx.AsyncClient with unittest.mock in Pytest, AsyncMock must be used instead of MagicMock for async methods like post/get to prevent TypeError when awaited.
# httpx.AsyncClient Mocking with AsyncMock ## 症状 - 在测试中使用 `patch.object(httpx.AsyncClient, 'post', return_value=mock_response)`。 - 运行时,代码中包含 `response = await client.post(...)` 的地方抛出 `TypeError: object MagicMock can't be used in 'await' expression`。 ## 根本原因 ### 原因 1: 异步函数的返回值必须是 Coroutine - **问题**: `httpx.AsyncClient.post` 是一个 `async def` 方法,调用它会返回一个可等待(awaitable)的协程。 - **为什么发生**: 默认的 `patch` 或 `MagicMock` 没有自动推断对象的异步特性时,它只是同步地返回了 `return_value`。当事件循环试图 `await` 这个同步的 `MagicMock` 对象时,就会报错。 - **解决方案**: 在 `patch` 参数里显式使用 `new=AsyncMock(return_value=...)` 或 `new_callable=AsyncMock`。 ## 代码解决方案 **❌ 错误写法:** ```python from unittest.mock import patch, MagicMock mock_response = MagicMock(status_code=200) # 当被 await 时会触发 TypeError! with patch.object(httpx.AsyncClient, 'post', return_value=mock_response): await my_crawler.fetch() ``` **✅ 正确写法:** ```python from unittest.mock import patch, MagicMock, AsyncMock mock_response = MagicMock(status_code=200) # Response 对象本身及其方法通常是同步的 # 正确!覆盖掉原来的方法,使其行为成为一个 AsyncMock with patch.object(httpx.AsyncClient, 'post', new=AsyncMock(return_value=mock_response)): await my_crawler.fetch() ``` 使用 `side_effect` 模拟循序多次请求: ```python with patch.object(httpx.AsyncClient, 'get', new=AsyncMock(side_effect=[mock_1, mock_2])): ... ``` ## 关键经验 - 针对任何 `async def` 的 Mock,必须保证它被调用时能走协程语境。 - 严格区分 **异步的请求方法** 与 **同步的响应对象**:`httpx.AsyncClient.get` 是异步的(需 `AsyncMock`),但它返回的 `Response` 对象上的 `.json()` 是同步的(需 `MagicMock` 即可)。
GitHub에서 보기