下面的代码显示了这个问题。
我可以成功地修补这个SomeClass
的对象实例和静态方法
但是,我似乎无法修补classmethods。
帮助非常感谢!
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()
通解
修补类方法的一种方法是使用new=classmethod(class_method)
而不是side_effects=class_method
.
这在一般情况下效果很好。
缺点使用new
,补丁对象不一定是Mock
,MagicMock
,AsyncMock
或PropertyMock
的实例(在回答的其余部分,我将只引用Mock
,因为所有其他都是它的子类)。
只有当您通过例如new=Mock(...)
或完全提交属性显式指定它为一个实例时,它才是这些实例的实例。
在这个答案的顶部提供的解决方案不会是这种情况。因此,当你尝试检查函数是否已经使用obj.class_method.assert_called()
被调用时,它会给出一个错误,说function has no attribute assert_called
,这是由于补丁对象不是Mock
的实例,而是function
。
不幸的是,目前在这种情况下,我看不到任何解决方案
new
和side_effect
的结论差异:
new
指定要给目标打补丁的对象(不一定是Mock
的实例)side_effect
指定当使用补丁而不使用new
时创建的Mock
实例的副作用他们也不能很好地发挥,所以只有一个可以/应该在同一个patch(...)
中使用。