如何正确Mock SQLAlchemy的DBSession链式查询?
问题分析与解决
你的问题出在没有正确模拟链式调用的层级关系,同时测试中的断言逻辑也和原代码的调用路径不匹配。我们一步步拆解来看:
原代码的调用链
原方法里的数据库调用是这样的:
db_session = DBSession() # 先实例化DBSession类,得到一个会话实例 keys = db_session.query(SomeClass).all() # 会话实例调用query,再调用all()
对应的链式层级是:DBSession()(实例) → .query(SomeClass) → .all()
你当前测试的错误点
- Mock路径错误:你设置的
DBSession.execute.query.execute.all.return_value完全不符合实际调用链,原代码里根本没有execute环节,属于无意义的路径。 - 断言逻辑错误:你用
DBSession.query('qwe').all()来断言,但原代码是先实例化DBSession(调用DBSession())再调用实例的query方法,而不是直接调用DBSession类的query方法。
正确的Mock写法
我们需要按链式调用的层级,逐层设置Mock的返回值:
@patch('app.modules.somemodule.DBSession') def test_asd(self, mock_db_session_class): # 1. 模拟DBSession()实例化后的会话对象 mock_session_instance = mock_db_session_class.return_value # 2. 模拟会话对象调用query()后返回的查询对象 mock_query = mock_session_instance.query.return_value # 3. 设置查询对象的all()方法返回预期结果 mock_query.all.return_value = [1, 2, 3] # 调用被测试的方法(比如你的get_all_keys) result = get_all_keys() # 断言结果符合预期 self.assertListEqual(result, [1, 2, 3]) # 可选:验证调用是否符合预期(这一步能帮你确认Mock是否匹配实际调用) mock_db_session_class.assert_called_once() # 确认DBSession()被调用了一次 mock_session_instance.query.assert_called_once_with(SomeClass) # 确认query被传入正确参数 mock_query.all.assert_called_once() # 确认all()被调用了一次
为什么这样写能生效?
mock_db_session_class.return_value对应DBSession()创建的实例,因为当你调用一个MagicMock类时,它的return_value就是实例化后的Mock对象。mock_session_instance.query.return_value对应实例调用query()后返回的查询对象,同理,后续的all.return_value就是最终要返回的结果列表。
这样整个链式调用的每一层都被正确Mock,就能和原代码的调用逻辑完全匹配了。
内容的提问来源于stack exchange,提问作者nejdetckenobi
相关产品推荐
相关产品推荐

