如何在unmocked类中使用autospec修补classmethod?

sca*_*nny 11 python static-methods mocking class-method python-mock

我想声明Python类中的一个类方法调用另一个带有一组参数的classmethod.我希望模拟的classmethod是"spec-ed",因此它会检测是否使用错误的参数调用它.

当我使用patch.object(.., autospec=True, ..)classmethod 补丁时,classmethod被替换为a NonCallableMagicMock并在我尝试调用它时引发错误.

from mock import patch

class A(object):

    @classmethod
    def api_meth(cls):
        return cls._internal_classmethod(1, 2, 3)

    @classmethod
    def _internal_classmethod(cls, n, m, o):
        return sum(n, m, o)

with patch.object(A, '_internal_classmethod') as p:
    print(type(p).__name__)

with patch.object(A, '_internal_classmethod', autospec=True) as p:
    print(type(p).__name__)
Run Code Online (Sandbox Code Playgroud)

产生输出:

MagicMock
NonCallableMagicMock
Run Code Online (Sandbox Code Playgroud)

我怎样才能得到一个特定的模拟器来判断_internal_classmethod它所属的类何时不被嘲笑?

Fel*_*ipe 7

有一个突出的错误报告(谷歌代码链接python错误跟踪链接)来解决这个问题.在修复程序合并之前,您可以尝试以下操作,这对我有用[ 2.7虽然我认为它也适用3.x].

def _patched_callable(obj):
    "Monkeypatch to allow autospec'ed classmethods and staticmethods."
    # See https://code.google.com/p/mock/issues/detail?id=241 and
    # http://bugs.python.org/issue23078 for the relevant bugs this
    # monkeypatch fixes
    if isinstance(obj, type):
        return True
    if getattr(obj, '__call__', None) is not None:
        return True
    if (isinstance(obj, (staticmethod, classmethod))
        and mock._callable(obj.__func__)):
        return True
    return False
_patched_callable._old_func = mock._callable
mock._callable = _patched_callable
Run Code Online (Sandbox Code Playgroud)

在monkeypatch之后,你应该能够mock.patch正常使用并且正确地修补静态和类方法.


AMa*_*nce 5

用来spec代替autospec,直接设置.

with patch.object(A, '_internal_classmethod', spec=A._internal_classmethod) as p:
    print(type(p).__name__)
Run Code Online (Sandbox Code Playgroud)

给我

MagicMock
Run Code Online (Sandbox Code Playgroud)

输出.

  • 这解决了获取NonCallableMagicMock的问题,但遗憾的是,它没有提供在模拟的classmethod上捕获调用签名不匹配的行为.这种行为很重要,因为它可以防止模拟测试通过,即使代码本身被破坏,也许可以通过更改方法的调用签名.我怀疑我正在寻找的行为是"部分autospec",也许mock还不支持那种事情. (7认同)