You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移到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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:17:06