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

Python单元测试如何mock/patch被模拟类内的多个方法

问题根因

你的测试代码存在4个核心问题:

  1. 直接patch了整个DataProcess类,把类替换成了MagicMock对象,类里原本写的run_task、validate_gathered_data等真实业务逻辑完全被架空,执行run_task()时只是调用了mock的空方法,根本不会走真实的调用链,validate_gathered_data自然不会被触发。
  2. 给gather_data设置返回值时,传入的是self.__get_mocked_dataset方法本身,没有加括号调用拿到实际的DataFrame,所以报错信息里会显示传入的是bound method对象。
  3. 测试文件导错了异常类名,源码里定义的是DataProcessException,你导入的RawDataException根本不存在。
  4. 代码里写错了方法名,把save_output_data写成了save_output_artifact;另外类中的辅助方法__get_mocked_dataset漏写了self参数,调用时会抛参数不匹配错误。
可行解决方案

核心原则:不要mock整个被测类,只需要mock掉会触发外部依赖的部分,保留被测业务逻辑的真实执行流程即可,以下提供两种常用写法:

写法1:直接替换实例方法(最易上手)

实例化真实的DataProcess对象,仅替换掉会触发数据库、存储服务调用的两个方法,用spy包裹校验方法保留原有逻辑:

from unittest.mock import Mock
import pandas as pd
import pytest

# 修正异常类导入
from src.main.run_data_process import DataProcess, DataProcessException


class TestDataProcess:
    # 补全self参数
    def __get_mocked_dataset(self):
        return pd.DataFrame(
            [[111, 222, 333], ['text_1', 'text_2', 'text_3'], [True, False, False]],
            columns=['col_1', 'col_2', 'col_3'])

    def test_gathered_data_is_validated_successfully(self):
        # 实例化真实业务对象
        dp = DataProcess()
        test_df = self.__get_mocked_dataset()
        # 仅mock会触发外部依赖的方法
        dp.gather_data = Mock(return_value=test_df)
        dp.save_output_data = Mock(return_value=None)
        # 用spy包裹校验方法,不改变原有执行逻辑,仅记录调用情况
        dp.validate_gathered_data = Mock(side_effect=dp.validate_gathered_data)

        # 执行真实业务流程
        dp.run_task()

        # 断言
        dp.validate_gathered_data.assert_called_once_with(test_df)
        dp.save_output_data.assert_called_once_with(test_df)

写法2:用patch.object规范打补丁

用unittest自带的patch.object上下文管理器做补丁,测试结束后会自动还原方法,不会污染其他测试用例:

from unittest.mock import patch
import pandas as pd
import pytest

from src.main.run_data_process import DataProcess, DataProcessException


class TestDataProcess:
    def __get_mocked_dataset(self):
        return pd.DataFrame(
            [[111, 222, 333], ['text_1', 'text_2', 'text_3'], [True, False, False]],
            columns=['col_1', 'col_2', 'col_3'])

    def test_gathered_data_is_validated_successfully(self):
        test_df = self.__get_mocked_dataset()
        dp = DataProcess()

        with patch.object(dp, 'gather_data', return_value=test_df), \
             patch.object(dp, 'save_output_data', return_value=None), \
             patch.object(dp, 'validate_gathered_data', wraps=dp.validate_gathered_data) as mock_validate:
            
            dp.run_task()
            mock_validate.assert_called_once_with(test_df)
            dp.save_output_data.assert_called_once_with(test_df)

最佳实践补充

更推荐直接mock最外层的外部依赖,不需要修改类内部方法,可以完整覆盖所有内部逻辑的测试:

def test_gathered_data_is_validated_successfully(self):
    test_df = self.__get_mocked_dataset()
    # 注意mock路径是被测文件中引用依赖的路径,不是依赖的原始导入路径
    with patch('src.main.run_data_process.DBConnection') as mock_db, \
         patch('src.main.run_data_process.DataStorageManager') as mock_storage:
        
        mock_db.return_value.run.return_value = test_df
        dp = DataProcess()
        dp.run_task()

        # 可以完整校验全链路调用
        mock_db.return_value.run.assert_called_once()
        mock_storage.return_value.save_output_object.assert_called_once_with(test_df)

内容的提问来源于stack exchange,提问作者anajbellini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:09:20