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

Python类打补丁与类方法打补丁的差异及测试问题解析

两种Python Mock方式的断言差异原因解析

先看你提供的代码示例:

class.py

class SomeClass:
  def __init__(self, some_value):
    self.some_value = some_value

  def add_to_value(self, add_value):
    self.some_value = self.some_value + add_value

function_thing.py

from my_pkg.class import SomeClass

def some_function():
    some_class_instance = SomeClass(5)
    some_class_instance.add_to_value(6)

test_function_thing.py

from my_pkg.function_thing import some_function
class TestSomeFunction(TestCase):
  # 此测试可行,能识别方法被传入6调用
  @patch("my_pkg.function_thing.SomeClass")
  def test_some_function_01(self, mock_some_class):
    instance_mock = mock_some_class.return_value
    some_function()
    instance_mock.add_to_value.assert_called_with(6)

  # 此测试不可行
  @patch("my_pkg.function_thing.SomeClass.add_to_value")
  def test_some_function_02(self, mock_add_to_value):
    some_function()
    # 此断言成功
    mock_add_to_value.assert_called_once()
    # 此断言失败,提示调用参数不是6而是某个对象
    mock_add_to_value.assert_called_with(6)

为什么test_some_function_01能正常工作?

当你用@patch("my_pkg.function_thing.SomeClass")把整个类Mock掉时,SomeClass变成了一个Mock类对象:

  1. 当some_function里执行SomeClass(5)创建实例,本质是调用这个Mock类的构造方法,Mock类的return_value就是它“返回”的实例Mock对象。
  2. 后续调用some_class_instance.add_to_value(6),实际是调用这个实例Mock的add_to_value方法,传递的参数就是6,所以assert_called_with(6)能精准匹配。

为什么test_some_function_02的第二个断言失败?

直接Mock类的方法SomeClass.add_to_value时,你替换的是类层面的方法绑定。而Python中调用实例方法的逻辑是:

  • 当你执行some_class_instance.add_to_value(6),Python会自动把实例some_class_instance作为第一个参数(也就是方法定义里的self)传递给方法。
  • 所以被Mock的add_to_value实际接收到的调用参数是(some_class_instance, 6),而不是你预期的(6)。
  • 这就是为什么assert_called_once()能过(确实被调用了一次),但assert_called_with(6)失败——因为实际参数是实例对象加6,不是只有6。

总结

如果要断言实例方法的调用参数,最优方式是Mock整个类,然后通过类Mock的return_value获取实例Mock,再断言实例Mock的方法调用。这种方式完全隔离了原类的实现,测试更可靠。

如果非要直接Mock类方法,断言时需要把实例对象也包含进去,但这样测试会耦合实例的具体状态,灵活性差,不推荐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:02:52