如何在Pytest中Mock SQLAlchemy Row对象?
解决SQLAlchemy Core测试中Row对象属性访问的问题
核心问题
你遇到的问题本质是混淆了SQLAlchemy Table结构定义和查询返回的Row数据对象:Table是数据库表的元数据描述,不能直接实例化;而服务层访问的是查询返回的Row对象(或其衍生对象),测试时需要构造这类支持属性访问的对象。
可行解决方案
方法一:构造真实的SQLAlchemy Row对象
直接用SQLAlchemy提供的Row类,结合表的列定义构造,完全匹配生产环境的返回结构:
from sqlalchemy import Row # 构造与User表字段对应的Row对象 user_row = Row(User.c.id, User.c.name)(11, "David") # 测试用例示例 async def test_fetch_users(mocker): # 模拟数据库连接和执行结果 mock_conn = mocker.Mock() mock_result = mocker.Mock() mock_result.all.return_value = [user_row] mock_conn.execute.return_value = mock_result # 调用待测试方法 repo = UserRepository() users = await repo.fetch_users(mock_conn) # 验证属性访问正常 assert users[0].id == 11 assert users[0].name == "David"
方法二:使用SQLAlchemy测试工具的MockRow
SQLAlchemy内置了测试用的MockRow,可以直接通过关键字参数构造,更简洁:
from sqlalchemy.testing.mock import MockRow # 直接按字段名构造 user_row = MockRow(id=11, name="David") # 测试时返回该对象即可,服务层的属性访问逻辑完全兼容
方法三:用标准库namedtuple轻量模拟
如果不想依赖SQLAlchemy内部类,用Python标准库的namedtuple就能实现相同的属性访问效果:
from collections import namedtuple # 定义与User表字段一致的namedtuple UserRow = namedtuple("UserRow", ["id", "name"]) user_row = UserRow(id=11, name="David") # 测试时返回该对象,服务层无需修改任何代码
关键注意点
- 永远不要直接调用Table对象(
User(...)),它是表结构的元数据,不是数据实例,这就是你触发TypeError: 'Table' object is not callable的原因。 - 服务层的属性访问只要求对象有对应名称的属性,所以只要构造的对象字段名与表列名一致,就能兼容生产和测试环境。
内容的提问来源于stack exchange,提问作者Sidharth Samant
相关产品推荐
相关产品推荐

