Как исправить classmethod с autospec в незащищенном классе?

Я хочу утверждать, что один метод класса в классе 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, если класс, к которому он принадлежит, не является макетом?


person scanny    schedule 30.08.2014    source источник


Ответы (2)


Есть незавершенный отчет об ошибке (ссылка на код Google и ссылка на систему отслеживания ошибок 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 и должным образом исправите статические и классовые методы.

person Felipe    schedule 02.06.2015

Используйте spec вместо autospec и установите его напрямую.

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

дает мне

MagicMock

для вывода.

person AManOfScience    schedule 17.09.2014
comment
Это решает проблему возврата NonCallableMagicMock, но, к сожалению, не обеспечивает поведение обнаружения несоответствия сигнатуры вызова в методе класса с имитацией. Такое поведение важно, потому что оно защищает от фальшивых тестов, которые проходят, даже если сам код неисправен, возможно, путем изменения сигнатуры вызова метода. Я подозреваю, что поведение, которое я ищу, является частичной автоспецификацией, и, возможно, mock еще не поддерживает такие вещи. - person scanny; 25.09.2014