【问题标题】:How to get `self` instance in `mock.Mock().call_args`?如何在`mock.Mock().call_args`中获取`self`实例?
【发布时间】:2021-02-23 18:31:52
【问题描述】:

我在修补虚拟类时观察到不一致的行为:

class A:

  def f(self, *args, **kwargs):
    pass

如果我手动修补该功能:

call_args_list = []
def mock_fn(*args, **kwargs):
  call_args_list.append(mock.call(*args, **kwargs))

with mock.patch.object(A, 'f', mock_fn):
  A().f(1, 2)

print(call_args_list)  # [call(<__main__.A object at 0x7f0da0c08b50>, 1, 2)]

正如预期的那样,mock_fn 是使用 self 参数 (mock_fn(self, 1, 2)) 调用的。

但是,如果我使用的是 mock.Mock 对象,则 self 参数会以某种方式从调用中移除:

mock_obj = mock.Mock()

with mock.patch.object(A, 'f', mock_obj):
  A().f(1, 2)

print(mock_obj.call_args_list)  # [call(1, 2)]

这种感觉不一致。 mock_obj 被称为 mock_obj(self, 1, 2),但 mock_obj.call_args == call(1, 2)。它从call_args 中删除self 参数。如何访问有界方法实例?

【问题讨论】:

    标签: python unit-testing mocking python-unittest


    【解决方案1】:
    with mock.patch.object(A, 'f', autospec=True) as mock_obj:
        A().f(1, 2)
    
    print(mock_obj.call_args_list)  # [call(<__main__.A object at 0x7fb2908fc880>, 1, 2)]
    

    来自the documentation

    如果您传递autospec=True [...],如果从实例中获取模拟函数,它将被转换为绑定方法。它将self 作为第一个参数传入 [...]

    【讨论】:

      【解决方案2】:

      来自 Python 控制台,help(mock.MethodType)

      创建一个绑定的实例方法对象。

      from unittest import mock
      
      class A:
      
        def f(self, *args, **kwargs):
          pass
      
      
      mock_obj = mock.Mock()
      a = A()
      with mock.patch.object(A, 'f', mock_obj):
          a.f(1, 2)
          print(mock_obj.call_args)
      
      # fixed self in call_args by patching
      # with a bound instance method mock
      mock_obj = mock.Mock()
      with mock.patch.object(A, 'f', mock.MethodType(mock_obj, a)):
          a.f(1, 2)
          print(mock_obj.call_args)
      

      输出:

      call(1, 2)
      call(<__main__.A object at 0x7ff8223e1dc0>, 1, 2)
      

      【讨论】:

      • 我不明白答案。我已经知道如何使用def mock_fn 提取self,如我的示例所示。但是,我想使用mock.Mock().call_args
      • @Conchylicultor :对不起,这个例子让你觉得 mock_fn 是必要的。我希望我的意图现在很清楚。
      • 感谢您的更新。但是,此解决方案假定 (1) 在调用 mock.patch 时已经创建了有界对象。 (2) 只会创建一个 A 实例。调用b = A() ; b.f() 将调用a.f 而不是b.f。这些假设都不适用于我的用例
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-09
      • 2013-06-11
      • 2010-10-12
      • 2019-07-08
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      相关资源
      最近更新 更多