PyTest中如何patch模块变量?loaded_data patch失败求助
问题解决方案
核心问题分析
你遇到的属性错误,本质是patch路径与函数内部变量引用的绑定关系不匹配:如果测试文件中直接导入update_data函数,函数会提前绑定原模块的loaded_data变量,此时单纯patch模块级的loaded_data不会生效;或者patch的目标路径写法有误。
具体解决方案
方案1:修正Patch路径与调用方式
如果不想修改原代码,确保测试时调用模块内的函数,同时patch模块级变量:
# 测试文件中导入整个datamanager模块 import datamanager from unittest.mock import patch def test_update_models(): mock_loaded_data = {'some_data': 'data_file'} # patch模块级的loaded_data with patch('datamanager.loaded_data', new=mock_loaded_data): # 调用模块内的update_data函数,而非直接导入的函数 datamanager.update_data()
或者如果必须直接导入函数,可patch函数__globals__中的变量:
from datamanager import update_data from unittest.mock import patch def test_update_models(): mock_loaded_data = {'some_data': 'data_file'} with patch('datamanager.update_data.__globals__["loaded_data"]', new=mock_loaded_data): update_data()
方案2:重构代码,让函数更易测试
这是更推荐的做法——摆脱对模块级变量的硬依赖,将loaded_data作为可选参数传入函数:
修改datamanager.py中的update_data函数:
def update_data(loaded_data=None): # 如果未传参,使用模块级变量作为默认值 if loaded_data is None: loaded_data = globals()['loaded_data'] for key, current_model in loaded_data.items(): mod_dir = os.path.join(BASE_DIR, key) if not os.path.exists(mod_dir): print("Model dir not present") continue model_files = os.listdir(mod_dir) if not model_files: print("Model dir is empty") continue
测试时直接传入mock数据,无需patch:
from datamanager import update_data def test_update_models(): mock_loaded_data = {'some_data': 'data_file'} update_data(loaded_data=mock_loaded_data)
方案3:结合Patch验证路径检查逻辑
你的核心需求是验证mod_dir不存在时的逻辑,所以需要同时mockos.path.exists返回False,并验证打印行为:
import datamanager from unittest.mock import patch def test_update_models(): mock_loaded_data = {'some_data': 'data_file'} with patch('datamanager.loaded_data', new=mock_loaded_data), \ patch('datamanager.os.path.exists', return_value=False), \ patch('builtins.print') as mock_print: datamanager.update_data() # 验证是否触发了预期的打印 mock_print.assert_called_with("Model dir not present")
内容的提问来源于stack exchange,提问作者S Andrew
相关产品推荐
相关产品推荐

