Python单元测试问题:Side Effect返回函数而非预期值
问题原因
你当前的mock逻辑搞反了Series.apply的调用关系:Series.apply方法的参数是要应用的函数(也就是你传入的self._format_col),而不是Series的单个元素。你给side_effect赋值的lambda接收的val其实是self._format_col这个函数对象,所以返回的是函数的字符串表示,导致结果列全是函数地址。
解决方案
推荐两种正确的mock方式,优先选第一种,更符合单元测试的设计原则:
方案1:Mock _format_col方法(推荐)
单元测试应聚焦验证业务逻辑是否正确调用了格式化函数,而非测试Pandas的apply功能。直接mock类中的_format_col方法,让它返回你期望的格式化结果:
from unittest.mock import patch import pandas as pd class MyClass: def _format_col(self, val): # 原格式化逻辑 return str(val) def process_data(self, source_table_df): source_table_df["col1"] = source_table_df["col1"].apply(self._format_col) return source_table_df def test_process_data(): test_df = pd.DataFrame({"col1": [1, 1, 1]}) with patch.object(MyClass, "_format_col") as mock_format: # 设置mock返回带引号的字符串,匹配你的期望结果 mock_format.side_effect = lambda val: f'"{str(val)}"' my_instance = MyClass() result_df = my_instance.process_data(test_df) # 验证结果是否符合预期 expected_df = pd.DataFrame({"col1": ['"1"', '"1"', '"1"']}) pd.testing.assert_frame_equal(result_df, expected_df) # 验证格式化函数被调用了3次 assert mock_format.call_count == 3
方案2:正确Mock Series.apply方法
如果你一定要mockSeries.apply,需要让mock模拟真实apply的行为:接收一个函数,对原Series的每个元素执行该函数并返回新Series,或者直接返回预设结果:
方式A:直接返回预设结果
from unittest.mock import patch import pandas as pd def test_process_data(): test_df = pd.DataFrame({"col1": [1, 1, 1]}) with patch("pandas.core.series.Series.apply") as mock_apply: # 让apply直接返回你期望的Series mock_apply.return_value = pd.Series(['"1"', '"1"', '"1"']) my_instance = MyClass() result_df = my_instance.process_data(test_df) expected_df = pd.DataFrame({"col1": ['"1"', '"1"', '"1"']}) pd.testing.assert_frame_equal(result_df, expected_df)
方式B:模拟真实apply的执行逻辑
from unittest.mock import patch import pandas as pd def mock_apply(self, func): # 模拟真实apply:遍历Series元素,用传入的函数处理每个值 return pd.Series([func(val) for val in self]) def test_process_data(): test_df = pd.DataFrame({"col1": [1, 1, 1]}) with patch("pandas.core.series.Series.apply", side_effect=mock_apply): my_instance = MyClass() result_df = my_instance.process_data(test_df) # 若原_format_col逻辑是转字符串,这里会得到不带引号的结果;若要带引号,仍需mock _format_col
内容的提问来源于stack exchange,提问作者noahsrc
相关产品推荐
相关产品推荐

