如何在未模拟的类中用autospec修补类方法?

11 投票
2 回答
5914 浏览
提问于 2025-04-19 00:51

我想确认在一个Python类里,一个类方法会用特定的参数去调用另一个类方法。我希望被模拟的类方法能够“规范化”,这样它就能检测到是否用错了参数的数量。

当我使用 patch.object(.., autospec=True, ..) 来替换这个类方法时,它被替换成了一个 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__)

这段代码会输出:

MagicMock
NonCallableMagicMock

我该如何在不模拟所属类的情况下,为 _internal_classmethod 获取一个规范化的模拟呢?

2 个回答

5

spec 替代 autospec,并直接设置它。

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

这样给我的结果是

MagicMock

作为输出。

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

在做了这个“猴子补丁”之后,你应该可以正常使用mock.patch,并且静态方法和类方法也能正确地被补丁处理。

撰写回答