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

Python单元测试断言scoped_session.commit()调用失败问题求助

Python单元测试断言scoped_session.commit()调用失败问题

场景与代码

我编写Python单元测试时,尝试断言scoped_session的.commit()方法被调用,但测试失败。相关代码如下:

main.py

from database import DBSession

def deactivate_user(user_id):
    db_session = DBSession()
    user = User(db_session).get(user_id)
    user.is_active = False
    db_session.commit()

def get_account(user_id):
    pass

database.py

from sqlalchemy.orm import sessionmaker, scoped_session
import settings

session_factory = sessionmaker(bind=create_engine(settings.CONNECTION_STRING))
DBSession = scoped_session(session_factory)

unit_test.py

from main import deactivate_user

def test_deactivate_user(mocker):
    mocked_account = mocker.patch('main.get_account', return_value=get_test_account())
    mocked_session = mocker.patch('database.DBSession', autospec=True)
    deactivate_user(123)
    mocked_account.assert_called()
    mocked_session.commit.assert_called()

错误信息

mocked_account.assert_called()执行正常,但mocked_session.commit.assert_called()失败,报错:

E   AssertionError: Expected 'commit' to have been called.

额外调试信息:

type(mocked_session) == <class 'unittest.mock.MagicMock'>
mocked_session.mock_calls == []

问题原因与解决办法

核心问题

  1. Patch位置错误:Python的mock遵循「使用位置优先」原则,你需要patch被测试代码(main.py)中实际导入使用的DBSession,而非定义它的database.py模块。
  2. 误解scoped_session的调用逻辑:DBSession是会话工厂,调用DBSession()才会返回实际的会话实例,commit()是这个实例的方法,而非工厂本身的方法。

修改后的测试代码

from main import deactivate_user

def test_deactivate_user(mocker):
    # Mock get_account
    mocked_account = mocker.patch('main.get_account', return_value=get_test_account())
    
    # 1. 创建mock会话实例,它才是拥有commit方法的对象
    mock_session_instance = mocker.Mock()
    # 2. Patch main里的DBSession,让它返回这个mock实例
    mocked_db_session = mocker.patch('main.DBSession', return_value=mock_session_instance)
    
    # 3. Mock User类及其get方法,避免依赖真实数据库操作
    mock_user = mocker.Mock(is_active=True)
    mocked_user_class = mocker.patch('main.User', return_value=mocker.Mock(get=lambda x: mock_user))
    
    deactivate_user(123)
    
    # 验证各个调用
    mocked_account.assert_called()
    mocked_db_session.assert_called_once()  # 验证DBSession()被调用
    mock_session_instance.commit.assert_called_once()  # 验证会话实例的commit被调用
    assert mock_user.is_active is False  # 额外验证用户状态被修改

内容的提问来源于stack exchange,提问作者user7692855

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:01:02