我如何修补python @classmethod来调用我的side_effect方法?

icomxhvb  于 2022-12-25  发布在  Python
关注(0)|答案(1)|浏览(108)

下面的代码显示了该问题。
我可以成功地修补此SomeClass的对象示例和静态方法
然而,我似乎无法修补类方法。
非常感谢帮助!

from contextlib import ExitStack
from unittest.mock import patch

class SomeClass:
    def instance_method(self):
        print("instance_method")

    @staticmethod
    def static_method():
        print("static_method")

    @classmethod
    def class_method(cls):
        print("class_method")

# --- desired patch side effect methods ----
def instance_method(self):
    print("mocked instance_method")

def static_method():
    print("mocked static_method")

def class_method(cls):
    print("mocked class_method")

# --- Test ---
obj = SomeClass()

with ExitStack() as stack:
    stack.enter_context(
        patch.object(
            SomeClass,
            "instance_method",
            side_effect=instance_method,
            autospec=True
        )
    )
    stack.enter_context(
        patch.object(
            SomeClass,
            "static_method",
            side_effect=static_method,
            # autospec=True,
        )
    )
    stack.enter_context(
        patch.object(
            SomeClass,
            "class_method",
            side_effect=class_method,
            # autospec=True
        )
    )

    # These work
    obj.instance_method()
    obj.static_method()

    # This fails with TypeError: class_method() missing 1 required positional argument: 'cls'
    obj.class_method()
oogrdqng

oogrdqng1#

一般溶液

修补类方法的一种方法是使用new=classmethod(class_method)而不是side_effects=class_method
这在总体上效果不错。

缺点

使用new,修补对象不再一定是MockMagicMockAsyncMockPropertyMock的示例(在答案的其余部分,我将只引用Mock,因为所有其他都是它的子类)。
只有当您通过new=Mock(...)或完全省略属性将其显式指定为一个属性时,它才是这些属性的示例。
答案顶部提供的解决方案不会出现这种情况。因此,当您尝试检查函数是否已使用obj.class_method.assert_called()调用时,它会给予错误消息function has no attribute assert_called,这是由于修补对象不是Mock的示例,而是function

遗憾的是,目前我看不到任何解决方案来解决这种情况下的不利因素

newside_effect之间的结论差异:

  • new指定使用什么对象修补目标(不一定是Mock的示例)
  • side_effect指定了Mock示例的side_effect,该示例在使用没有new的补丁时创建。此外,它们不能很好地配合使用,因此只能/应该在同一个patch(...)中使用其中一个。

相关问题