为何pytest patch无法Mock动态获取的Pandas read_csv函数?
问题:Mock动态字典中的Pandas read_csv函数失效
业务代码示例:
import pandas as pd format_read_func_mapping = {"csv": pd.read_csv, "parquet": pd.read_parquet} def my_func(s3_path, file_format): read_func = format_read_func_mapping[file_format] df = read_func(f"{s3_path}") return df
测试代码:
from unittest.mock import patch @patch(f"{MODULE_PATH}.pd.read_csv") def test_my_func(self, mock_read_csv): mock_read_csv.side_effect = [my_test_data_frame] my_func(dummy_s3_path, "csv")
现象:期望测试使用Mock返回测试数据,但实际调用了真实的pandas.read_csv;若在my_func中直接调用pd.read_csv而非通过字典获取,Mock能正常工作。
原因分析
这不是pytest的限制,是Mock方式没匹配代码的执行逻辑:
- 模块加载时,
format_read_func_mapping字典就已经存储了真实的pd.read_csv函数引用 - 你用
patch(f"{MODULE_PATH}.pd.read_csv")修改的是模块命名空间里的pd.read_csv,但字典里保存的还是最初的真实函数引用,所以my_func调用的是字典里的真实函数,而非Mock版本
解决方法
方法1:延迟获取函数引用
修改字典存储函数名称,每次调用时通过getattr从pd中动态获取,确保每次都能拿到最新的(包括被Mock的)函数引用:
import pandas as pd format_read_func_mapping = {"csv": "read_csv", "parquet": "read_parquet"} def my_func(s3_path, file_format): read_func = getattr(pd, format_read_func_mapping[file_format]) df = read_func(f"{s3_path}") return df
方法2:直接Mock字典中的函数引用
跳过模块里的pd.read_csv,直接patch字典中存储的那个函数引用:
from unittest.mock import patch @patch(f"{MODULE_PATH}.format_read_func_mapping['csv']") def test_my_func(self, mock_read_csv): mock_read_csv.return_value = my_test_data_frame my_func(dummy_s3_path, "csv")
方法3:动态生成函数映射
把字典改成每次调用时动态生成的逻辑,确保每次都从pd中取最新函数:
import pandas as pd def get_read_func(file_format): func_map = {"csv": pd.read_csv, "parquet": pd.read_parquet} return func_map[file_format] def my_func(s3_path, file_format): read_func = get_read_func(file_format) df = read_func(f"{s3_path}") return df
内容的提问来源于stack exchange,提问作者Sapience
相关产品推荐
相关产品推荐

