为何session.commit()与session.flush()的assert_not_called未生效?
问题原因及解决办法
你的测试能通过,核心问题是mock的层级没搞对:
- 你patch的
session_scope_retries是个上下文管理器函数,当代码执行with session_scope_retries() as db_session时,真正拿到的db_session是这个上下文管理器__enter__()方法返回的对象。 - 但你现在直接在被patch的
session_scope_retries对象上断言flush和commit是否被调用,而这两个方法其实是调用在__enter__返回的会话实例上,根本不是patch的那个函数对象。所以原来的断言相当于在检查一个完全没被调用过的方法,自然会通过。
修复后的测试代码
def test_bad_currency_data_not_persisted(mock_check_currency, metadata_dict): ... # 先创建一个模拟的数据库会话对象,包含flush和commit方法 mock_db_session = Mock() with patch('exchanges.exchange.session_scope_retries') as mock_session_scope: # 让上下文管理器返回我们创建的模拟会话对象 mock_session_scope.return_value.__enter__.return_value = mock_db_session check_currency(security_files_generated) # 对真正被调用的模拟会话对象做断言 mock_db_session.flush.assert_not_called() mock_db_session.commit.assert_not_called()
额外说明
原来的测试里,db_session.flush和db_session.commit其实是在访问被patch的session_scope_retries函数的属性,这个函数本身从来没被调用过这两个方法,所以assert_not_called()肯定会通过。只有正确mock出上下文管理器返回的会话实例,才能准确捕获到flush和commit的调用行为,让测试符合预期。
内容的提问来源于stack exchange,提问作者ifrj
相关产品推荐
相关产品推荐

