You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

单元测试Mock SQLAlchemy Session上下文管理器后,目标函数未使用内存数据库会话的问题排查与解决

单元测试Mock SQLAlchemy Session上下文管理器后,目标函数未使用内存数据库会话的问题排查与解决

我来帮你分析下问题出在哪,以及怎么修复:

问题根源拆解

你当前的mock方式有两个核心问题:

  1. Mock上下文管理器的姿势不对:你直接给mock_session.__enter__赋值Mock对象,但patch出来的Mock是一个可调用对象——当代码执行with Session()时,实际上是先调用Session()得到上下文管理器实例,再调用这个实例的__enter__方法。你直接修改mock_session__enter__属性,并没有影响到Session()调用后返回的实例的__enter__逻辑,所以目标函数里的会话还是空的mock对象,根本没连上你的内存数据库。
  2. 测试数据添加的方式错误:你用with mock_session as session:来添加测试数据,这里的session是mock出来的假对象,不是你创建的内存会话,所以数据根本没真正写入到内存数据库里。

具体修复步骤

1. 正确初始化内存数据库与会话

首先要把内存数据库的会话和原代码的Session上下文管理器解耦,自己创建独立的会话工厂:

@patch("app.helpers.db_helper.Session")
def test_get_users_to_query(self, mock_session_ctx) -> None:
    # 1. 创建内存SQLite引擎
    self.engine = create_engine("sqlite:///:memory:")
    # 2. 创建内存数据库专属的会话工厂
    self.session_factory = sessionmaker(bind=self.engine)
    # 3. 生成实际的内存会话
    self.db_session = self.session_factory()
    # 4. 创建所有表结构
    Base.metadata.create_all(self.engine)

2. 往内存会话里添加测试数据

直接操作自己的内存会话,把测试数据真正写入内存库:

# 添加测试用户到内存会话
    fake_user1 = User(user_name="jdb1", flag=False)
    fake_user2 = User(user_name="jdb2", flag=True)
    self.db_session.add(fake_user1)
    self.db_session.add(fake_user2)
    self.db_session.commit()

3. 正确Mock Session上下文管理器

让被patch的Session()上下文管理器,在进入时返回你的内存会话:

# 关键:让Session()调用返回的上下文管理器,__enter__方法返回内存会话
    # Session() -> 上下文管理器实例 -> __enter__() -> 返回我们的内存会话
    mock_session_ctx.return_value.__enter__.return_value = self.db_session
    # 可选:设置__exit__方法避免报错
    mock_session_ctx.return_value.__exit__.return_value = None

4. 调用目标函数并验证结果

注意原函数get_users_to_query的默认flag参数是False,如果要查flag=True的用户,记得传参:

# 调用目标函数,查询flag=True的用户
    users_to_query = get_users_to_query(flag=True)
    # 验证结果
    print("Users:", users_to_query)
    # 断言验证(可选,更规范的测试方式)
    self.assertEqual(len(users_to_query), 1)
    self.assertEqual(users_to_query[0]["user_name"], "jdb2")

额外注意点

  • 确保patch的路径绝对正确:必须是目标函数get_users_to_query导入Session的路径(也就是app.helpers.db_helper.Session),路径错了mock完全不会生效。
  • 原代码里的User模型要正确继承自Base,否则Base.metadata.create_all不会创建users表。

备注:内容来源于stack exchange,提问作者abinitio

火山引擎 最新活动