迁移到redis.asyncio后单元测试报错:无法await非可等待对象
解决AsyncMock指定spec=Redis时的await表达式错误问题
问题原因
当你给AsyncMock指定spec=redis.Redis(同步客户端类)时,Mock会继承同步Redis方法的返回类型(比如bool、list、bytes这类非协程对象)。但异步Redis客户端(redis.asyncio.Redis)的方法实际返回的是协程对象,需要通过await调用。这种不匹配导致Mock出来的方法直接返回普通类型,而你的代码仍在await它,最终抛出TypeError: object bool/list/bytes can't be used in 'await' expression。
解决方案
1. 改用异步Redis类作为spec
直接将spec指定为异步客户端类redis.asyncio.Redis,这样Mock会自动继承异步方法的签名,返回可await的协程对象,和实际代码的调用逻辑完全匹配。
from redis.asyncio import Redis from unittest.mock import AsyncMock # 正确创建兼容异步的Mock mock_redis = AsyncMock(spec=Redis) # 设置返回值时无需手动包装,AsyncMock会自动处理成可await对象 mock_redis.get.return_value = b"cached_value" mock_redis.exists.return_value = True
2. 手动包装返回值为协程对象
如果因某些原因必须使用同步Redis的spec,可以手动将每个Mock方法的返回值包装成协程:
import asyncio from redis import Redis from unittest.mock import AsyncMock mock_redis = AsyncMock(spec=Redis) # 用asyncio.coroutine包装普通返回值,生成可await的协程 mock_redis.get.return_value = asyncio.coroutine(lambda: b"cached_value")() mock_redis.exists.return_value = asyncio.coroutine(lambda: True)()
3. 使用create_autospec生成异步兼容Mock
Python 3.10+版本可以用create_autospec,指定异步类并开启async=True参数,自动生成符合异步方法签名的Mock:
from redis.asyncio import Redis from unittest.mock import create_autospec # 创建严格匹配异步Redis类的Mock mock_redis = create_autospec(Redis, spec_set=True, async=True) mock_redis.hgetall.return_value = {b"key": b"value"}
注意事项
- 迁移到异步Redis后,测试Mock的核心要求是:所有被
await的方法必须返回协程对象,这是同步/异步Redis客户端的核心差异。 - 手动测试正常是因为实际的异步Redis客户端会正确返回协程,而错误的Mock配置打破了这个行为。
内容的提问来源于stack exchange,提问作者Ignac96
相关产品推荐
相关产品推荐

