You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 05:38:11