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

如何针对类中特定方法Mock/Patch其内部调用的方法?

解决方案:基于调用栈的条件Mock

要实现仅当bar_method被method_that_use_bar_function调用时Mock,其他场景保留真实逻辑,可以通过检查调用栈区分调用来源,结合unittest.mock的side_effect实现条件化Mock。

实现步骤

1. 编写条件化Mock的副作用函数

利用inspect模块获取调用栈,识别发起调用的上层方法,决定返回Mock值还是执行真实逻辑:

import inspect
from src.bar import Bar

def conditional_bar_method():
    # 遍历调用栈,跳过当前函数和Mock自身的栈帧
    for frame_info in inspect.stack()[1:]:
        caller_func = frame_info.function
        # 判断调用来源
        if caller_func == "method_that_use_bar_function":
            return "mocked_result"
        elif caller_func == "method_that_use_bar_function_too":
            # 执行真实的bar_method逻辑
            return Bar().bar_method()
    # 其他未知调用场景默认返回真实结果
    return Bar().bar_method()

2. 编写测试用例

使用unittest.mock.patch替换Bar.bar_method,并将上述副作用函数传入:

from unittest.mock import patch
from runner import method_to_run_all_my_code

def test_conditional_mock():
    with patch("src.bar.Bar.bar_method", side_effect=conditional_bar_method):
        final_result = method_to_run_all_my_code()
        
        # 验证结果是否符合预期:第一个调用Mock,第二个调用真实方法
        assert final_result == "Use 1 - mocked_resultUse 2 - real method"

原理说明

  • inspect.stack()返回当前程序的调用栈列表,每个元素包含调用方的函数名、代码位置等信息。
  • 通过遍历栈帧,可精准识别Foo类的哪个方法调用了bar_method,从而执行对应逻辑。
  • 这种方式无需修改业务代码,完全在测试层实现条件Mock。

备选方案(允许修改业务代码时)

如果可以微调业务代码,也可以通过给bar_method传递标识参数区分调用场景:

修改src/foo.py:

class Foo:
    def __init__(self) -> None:
        self.bar = Bar()
    
    def method_that_use_bar_function(self):
        # 传递调用场景标识
        result = self.bar.bar_method(caller="create_user")
        print("[Foo] Use 1 - " + result)
        return "Use 1 - " + result
    
    def method_that_use_bar_function_too(self):
        result = self.bar.bar_method(caller="get_user")
        print("[Foo] Use 2 - ", result)
        return "Use 2 - " + result

修改src/bar.py:

class Bar:
    def bar_method(self, caller=None):
        print("[Bar] this is a real method of bar")
        return "real method"

测试用例中通过参数判断Mock:

from unittest.mock import patch
from src.bar import Bar
from runner import method_to_run_all_my_code

def test_conditional_mock_with_param():
    def side_effect(caller=None):
        if caller == "create_user":
            return "mocked_result"
        else:
            return Bar().bar_method(caller)
    
    with patch("src.bar.Bar.bar_method", side_effect=side_effect):
        final_result = method_to_run_all_my_code()
        assert final_result == "Use 1 - mocked_resultUse 2 - real method"

这种方式更直观,性能也更好,但需要调整业务代码,适合可修改代码的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:03:15