如何在pytest中全局mock函数write_sql的所有实例?
全局Mock
write_sql 所有实例的优化方案 问题背景
你当前通过为每个使用write_sql的模块单独编写fixture实现Mock,但存在重复代码问题。直接Mockwrite_sql所属的原模块sql_services无效,原因是业务模块采用from sql_services import write_sql的导入方式——这会在模块本地命名空间创建一个指向原函数的独立引用,后续调用的是该本地引用,而非原模块的函数。
解决方案
方案1:统一导入方式(推荐,若允许修改业务代码)
将所有业务模块的导入方式改为引用原模块的形式,而非直接导入函数:
修改sandbox.py(及其他类似模块):
import sql_services def do_a_write(): df = # logic to populate a dataframe sql_services.write_sql(df, "schema.table")
此时只需保留一个全局fixture即可Mock所有调用:
# conftest.py import pytest from unittest.mock import MagicMock from ds_services import sql_services @pytest.fixture(autouse=True) def mock_write_sql(monkeypatch): mock = MagicMock() monkeypatch.set_attr(sql_services, "write_sql", mock) return mock
方案2:批量Mock所有目标模块(无需修改业务代码)
如果无法调整业务代码的导入方式,可以在单个fixture中批量处理所有需要Mock的模块,避免重复编写fixture:
基于monkeypatch实现
# conftest.py import pytest from unittest.mock import MagicMock @pytest.fixture(autouse=True) def mock_all_write_sql(monkeypatch): mock_write = MagicMock() # 列出所有导入了write_sql的模块路径 target_modules = [ "sandbox.write_sql", "sandbox2.write_sql", # 添加其他需要Mock的模块路径 ] for target in target_modules: monkeypatch.set_attr(target, mock_write) return mock_write
基于pytest-mock插件实现(更简洁)
先安装插件:pip install pytest-mock,然后编写fixture:
# conftest.py import pytest from unittest.mock import MagicMock @pytest.fixture(autouse=True) def mock_all_write_sql(mocker): mock_write = MagicMock() # 批量指定需要Mock的目标 targets = { "sandbox.write_sql": mock_write, "sandbox2.write_sql": mock_write, # 添加其他目标 } mocker.patch.multiple(**targets) return mock_write
说明
方案1从根源上避免了多模块Mock的重复工作,是更优的长期解决方案;方案2适用于无法修改业务代码的场景,通过批量处理减少重复代码。
内容的提问来源于stack exchange,提问作者Jacob Gladman
相关产品推荐
相关产品推荐

