asyncmock仅支持python 3.8+,低版本需升级或用patch+协程模拟;patch必须作用于调用位置而非定义位置;return_value自动包装为协程但类型非真实,需side_effect或cast确保类型;嵌套await需显式配置子属性为asyncmock。

AsyncMock 在 Python 3.8+ 中才能直接使用
Python 3.7 及更早版本没有 AsyncMock,强行导入会报 NameError: name 'AsyncMock' is not defined。如果你的项目还跑在 3.7 上,要么升级解释器,要么用 unittest.mock.patch 配合手动返回 coroutine 对象(比如用 asyncio.sleep(0) 或 mock.AsyncMock 的 backport 库 asynctest —— 但注意它已停止维护)。
实操建议:
- 检查 Python 版本:
python --version,确认 ≥ 3.8 - 直接导入:
from unittest.mock import AsyncMock,不用再装第三方包 - 若用 pytest,确保 pytest ≥ 6.2(对
AsyncMock的await行为修复更完整)
用 AsyncMock 替换 async def 函数时必须 patch 到调用位置
常见错误是 patch 了定义处(比如 @patch('mylib.fetch_data')),但测试代码实际 import 并调用的是 from mylib import fetch_data —— 这时 patch 失效,因为 mock 没覆盖到被引用的对象。
正确做法是 patch **测试模块中如何导入并使用该函数的位置**。例如:
# test_api.py
from myapp.api import call_service # ← 这里用了 mylib.fetch_data
<p>@patch('myapp.api.fetch_data') # ✅ patch 调用方所在模块里的名字
async def test_call_service(mock_fetch):
mock_fetch.return_value = {'ok': True}
result = await call_service()
assert result['ok']
</p>
关键点:
-
AsyncMock和普通Mock一样,遵循“patch 导入点”原则,不是 patch 定义点 - 如果函数是
await fetch_data(),return_value设成普通值即可(AsyncMock会自动包装成协程);若需控制返回协程的行为(如抛异常),用side_effect返回Exception或awaitable
AsyncMock.return_value 不等于 awaitable,要小心类型断言失败
当你写 mock_fn.return_value = {'data': 1},await mock_fn() 确实能返回该字典——但它的返回类型其实是 Mock,不是 dict。如果被测函数或类型检查器(如 mypy)做了严格类型注解(例如声明返回 dict[str, Any]),运行时虽不报错,静态检查可能失败,或引发 isinstance 判断误判。
解决方式:
- 需要真实类型时,用
side_effect返回一个真正的协程:mock_fn.side_effect = lambda: asyncio.sleep(0) or {'data': 1} - 或者用
AsyncMock(return_value=...)后,显式 cast:mock_fn.return_value = cast(dict, {'data': 1})(配合typing.cast) - 避免在 mock 上做
isinstance(result, dict)这类判断;改用hasattr(result, 'keys')或 duck typing
测试嵌套 await 时,AsyncMock 默认不递归 mock awaitable 属性
比如你 mock 了一个返回对象的异步方法:resp = await http_client.get(...),然后又写 await resp.json()。如果只 mock get,resp 是个 AsyncMock,但它的 json 属性默认还是普通 Mock,不能 await —— 此时会报 TypeError: object AsyncMock can't be used in 'await' expression(因为 resp.json 不是协程)。
正确做法是让嵌套属性也支持 await:
- 设置
resp.json = AsyncMock(return_value={'id': 123}) - 或初始化时用
AsyncMock的configure_mock:resp.configure_mock(json=AsyncMock(return_value={'id': 123})) - 更简洁:用
AsyncMock(spec=type(real_resp))(前提是 real_resp 类型有明确的异步方法签名)
这容易被忽略,尤其当 API 客户端封装多层 await 时,漏掉一层就会卡在 await 报错,而不是业务逻辑出错。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











