如何Mock Python脚本导入阶段调用的SQLAlchemy create_engine方法?
解决导入阶段执行的create_engine Mock问题
问题核心出在模块导入时机:database_wrapper.py里的engine = create_engine(...)是在模块被导入时立即执行的,你之前的所有patch操作都是在模块已经导入完成后才生效,自然无法拦截到初始的create_engine调用。要解决这个问题,必须保证mock在模块导入前就生效,同时选对patch的目标位置。
修正后的测试代码
from unittest import TestCase from unittest.mock import patch, MagicMock class TestMicroservice(TestCase): @patch('database_wrapper.create_engine') def test_1(self, create_engine_mock): # 1. 配置mock:给create_engine返回一个带connect方法的假引擎 mock_engine = MagicMock() mock_connect = MagicMock() mock_engine.connect.return_value = mock_connect create_engine_mock.return_value = mock_engine # 2. 必须在patch生效后才导入目标模块 from main import do_something do_something() # 3. 验证调用是否符合预期(可选) create_engine_mock.assert_called_once_with("connection_uri") mock_engine.connect.assert_called_once()
关键注意事项
- 禁止提前导入目标模块:测试文件顶部绝对不能写
import main或import database_wrapper,否则模块导入阶段create_engine已经执行,mock完全赶不上拦截时机。 - 选对patch目标:因为
database_wrapper里是from sqlalchemy import create_engine,相当于把create_engine复制到了database_wrapper的命名空间里,所以必须patchdatabase_wrapper.create_engine,而非sqlalchemy.create_engine或其他路径。 - 补全mock的必要方法:原代码中
update_database会调用engine.connect(),所以你的mock引擎必须模拟出connect方法(用MagicMock实现),否则运行时会触发属性不存在的报错。
如果你的测试目的只是验证do_something调用了update_database,可以保留@patch('main.update_database')的装饰器,但如果要测试update_database使用mock引擎的逻辑,就不能patch它,要让它真实执行,此时上面的代码完全适用。
内容的提问来源于stack exchange,提问作者DarioB
相关产品推荐
相关产品推荐

