Проверка Python, если метод вызывается без насмешки

class A():
    def tmp(self):
        print("hi")

def b(a):
    a.tmp()

Чтобы проверить, вызван ли метод tmp в b, рекомендуется

a = A()
a.tmp = MagicMock()
b(a)
a.tmp.assert_called()

Но TMP здесь высмеивается и не приводит к "hi" печатать.

Я хотел бы, чтобы мой модульный тест проверял, вызван ли метод tmp, без насмешек.

Это возможно?

Я знаю, что это не стандартная вещь, которую следует ожидать при написании юнитов. Но мой вариант использования (что немного сложнее) требует этого.

3 ответа

Решение

Вы можете установить Mock.side_effect быть оригинальным методом.

from unittest.mock import MagicMock

class A():
    def tmp(self):
        print("hi")

def b(a):
    a.tmp()

a = A()
a.tmp = MagicMock(side_effect=a.tmp)
b(a)
a.tmp.assert_called()

когда side_effect является функцией (или связанным методом в данном случае, который является своего рода функцией), вызывая Mock также назову side_effect с теми же аргументами.

Mock() Звонок вернется независимо от side_effect возвращается, если он не возвращает unnittest.mock.DEFAULT синглтон. Тогда он вернется Mock.return_value вместо.

В дополнение к ответу @Patrick Haugh вы также можете передать функциюwrapsаргумент (и он кажется мне семантически более правильным).

wraps: элемент для обертывания фиктивного объекта. Если wraps не None, то вызов Mock передаст вызов завернутому объекту (возвращая реальный результат). Доступ к атрибуту на макете вернет объект Mock, который обертывает соответствующий атрибут обернутого объекта (поэтому попытка доступа к несуществующему атрибуту вызовет AttributeError).

      a = A()
a.tmp = MagicMock(wraps=a.tmp)
b(a)
a.tmp.assert_called()

Или вы можете украсить метод для тестирования:

def check_called(fun):
    def wrapper(self, *args, **kw):
        attrname = "_{}_called".format(fun.__name__)
        setattr(self, attrname, True)
        return fun(self, *args, **kw)
    return wrapper


a = A()
a.tmp = check_called(a.tmp)
b(a)
assert(getattr(a, "_tmp_called", False))

но MagicMock's side_effect это определенно лучшее решение, если вы уже используете Mock;)

Другие вопросы по тегам