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

测试Flask路由时,如何Mock MySQLdb callproc以模拟存储过程存在?

解决Flask单元测试中模拟MySQL存储过程不存在的问题

你的问题核心在于:当前的Mock没有真正拦截到cursor.callproc的实际数据库调用,导致测试代码还是去真实的测试数据库里查找存储过程,自然会报错。下面给你两种可行的解决方案,帮你彻底解决这个问题:

方案一:精准Mock当前测试用到的Cursor实例

这种方式更聚焦,只针对当前测试用例中的Cursor对象进行Mock,不会影响其他测试的行为:

@unittest.mock.patch('flask_login.utils._get_user')
@unittest.mock.patch('flask_sqlalchemy.SQLAlchemy')
def test_attendances_management(self, SQLAlchemy, current_user):
    # 配置当前用户的Mock
    user = MagicMock()
    user.role.name = 'Administrator'
    user.id = 1
    current_user.return_value = user

    # 构建SQLAlchemy及数据库连接的Mock链
    sqlalchemy = SQLAlchemy()
    mock_raw_conn = MagicMock()
    mock_cursor = MagicMock()

    # 关键:给Cursor的callproc方法设置Mock返回值,模拟存储过程的执行结果
    mock_cursor.callproc.return_value = ((1, 3, 4),)
    
    # 把Mock对象串起来
    sqlalchemy.engine.raw_connection.return_value = mock_raw_conn
    mock_raw_conn.cursor.return_value = mock_cursor

    # 发起测试请求
    response = self.client.get('attendances/management/3/2020/11')
    self.assertEqual(response.status_code, 200)

    # 可选:验证存储过程是否被正确调用(参数是否符合预期)
    mock_cursor.callproc.assert_called_once_with("get_project_members", [3, 11, 2020])

方案二:全局Mock MySQLdb的Cursor类

如果你的多个测试用例都需要模拟存储过程调用,可以直接Mock MySQLdb的Cursor基类,这样所有Cursor实例的callproc都会被拦截:

@unittest.mock.patch('flask_login.utils._get_user')
@unittest.mock.patch('MySQLdb.cursors.Cursor.callproc')
@unittest.mock.patch('flask_sqlalchemy.SQLAlchemy')
def test_attendances_management(self, SQLAlchemy, mock_callproc, current_user):
    # 配置当前用户Mock
    user = MagicMock()
    user.role.name = 'Administrator'
    user.id = 1
    current_user.return_value = user

    # 配置SQLAlchemy相关Mock
    sqlalchemy = SQLAlchemy()
    mock_connection = MagicMock()
    mock_cursor = MagicMock()
    sqlalchemy.engine.raw_connection.return_value = mock_connection
    mock_connection.cursor.return_value = mock_cursor

    # 设置存储过程的模拟返回值
    mock_callproc.return_value = ((1, 3, 4),)

    # 发起测试请求
    response = self.client.get('attendances/management/3/2020/11')
    self.assertEqual(response.status_code, 200)

    # 验证调用参数
    mock_callproc.assert_called_once_with("get_project_members", [3, 11, 2020])

为什么你的原有代码会失败?

你之前的写法sqlalchemy.engine.raw_connection.cursor.callproc("get_project_members", [3, 9, 2020]).return_value是错误的——Mock方法的返回值应该直接设置给方法本身,而不是在"调用"Mock方法后设置。另外你还写错了参数顺序(请求里的月份是11,你写的是9),这也可能导致后续逻辑出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 15:42:46