我有兴趣使用 cls 的值和其他参数来修补 Schema 类中名为 _validate 的类方法以及替换的 fn 。
对于上下文,ArrayHoldingAnyType 继承自 Schema,实例化时会调用 _validate。 当我使用下面的代码尝试时,cls 的值不是一个类。如何修复 cls 变量?
def test_validate_called_n_times(self):
def replacement_validate(cls, *args):
# code which will return the correct values
with patch.object(Schema, '_validate', new=replacement_validate) as mock_validate:
path_to_schemas = ArrayHoldingAnyType(['a'])
# I will check that the mock was called a certain number of times here with specific inputs
所以这里的问题是 replacement_validate 中缺少 classmethod 装饰器。 这解决了它:
def test_validate_called_n_times(self):
@classmethod
def replacement_validate(cls, *args):
# code which will return the correct values
with patch.object(Schema, '_validate', new=replacement_validate) as mock_validate:
path_to_schemas = ArrayHoldingAnyType(['a'])
# I will check that the mock was called a certain number of times here with specific inputs
也许它对某人有帮助 - 这是我迄今为止所取得的成就(使用@spacether答案):
class A:
@classmethod
def f(cls, *args, **kwargs):
print('Original A.f() called with', cls, args, kwargs)
with mock.patch.object(
A,
'f',
new=classmethod(mock.MagicMock(side_effect=A.f.__func__))
) as patched:
A.f(1, 2)
print(patched)
print(patched.__func__)
print(patched.__func__.call_args)
输出是
Original A.f() called with <class '__main__.A'> (1, 2) {}
<classmethod(<MagicMock id='5089796880'>)>
<MagicMock id='5089796880'>
call(<class '__main__.A'>, 1, 2)
--所以返回的修补对象是一个
classmethod
类型对象,为了获取模拟,我们需要访问它的 __func__
属性。
这里还有一个更方便的版本,作为一个单独的函数,它接受一个可选的可调用对象并返回一个带有
.mock
属性的包装器:
def patch_classmethod(class_, method_name, new_method=None):
"""by default - call original method; to get the mock object please use .mock attribute of the returned object"""
if new_method is None:
new_method = getattr(class_, method_name).__func__
class ClassmethodMockContainer(classmethod):
@property
def mock(self) -> mock.Mock:
return self.__func__
mocked_method: Callable = mock.MagicMock(side_effect=new_method)
return mock.patch.object(class_, method_name, new=ClassmethodMockContainer(mocked_method))
with patch_classmethod(A, 'f') as patched:
A.f(1, 2)
print(patched)
print(patched.mock)
print(patched.mock.call_args)
with patch_classmethod(
A,
'f',
new_method=lambda cls, *a, **kw: print('hello', cls, a, kw),
) as patched:
A.f(1, 2)
print(patched)
print(patched.mock)
print(patched.mock.call_args)
输出:
Original A.f() called with <class '__main__.A'> (1, 2) {}
<classmethod(<MagicMock id='5194966864'>)>
<MagicMock id='5194966864'>
call(<class '__main__.A'>, 1, 2)
hello <class '__main__.A'> (1, 2) {}
<classmethod(<MagicMock id='5178984080'>)>
<MagicMock id='5178984080'>
call(<class '__main__.A'>, 1, 2)