Подтвердить что ты не робот

Как высмеивать свойство readonly с макетом?

Как вы издеваетесь над свойством readonly с mock?

Я пробовал:

setattr(obj.__class__, 'property_to_be_mocked', mock.Mock())

но проблема в том, что он применяется ко всем экземплярам класса..., который разбивает мои тесты.

Есть ли у вас другая идея? Я не хочу издеваться над полным объектом, только это конкретное свойство.

4b9b3361

Ответ 1

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

В документации указано unittest.mock.PropertyMock: Макет, предназначенный для использования в качестве свойства или другого дескриптора для класса. PropertyMock предоставляет методы __get__ и __set__, поэтому вы можете указать возвращаемое значение при его извлечении.

Вот как:

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

def test(unittest.TestCase):
    with mock.patch('MyClass.last_transaction', new_callable=PropertyMock) as mock_last_transaction:
        mock_last_transaction.return_value = Transaction()
        myclass = MyClass()
        print myclass.last_transaction
        mock_last_transaction.assert_called_once_with()

Ответ 2

Собственно, ответ был (как обычно) в документации, просто я применил патч к экземпляру вместо класса когда я последовал их примеру.

Вот как это сделать:

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

В тестовом наборе:

def test():
    # Make sure you patch on MyClass, not on a MyClass instance, otherwise
    # you'll get an AttributeError, because mock is using settattr and
    # last_transaction is a readonly property so there no setter.
    with mock.patch(MyClass, 'last_transaction') as mock_last_transaction:
        mock_last_transaction.__get__ = mock.Mock(return_value=Transaction())
        myclass = MyClass()
        print myclass.last_transaction

Ответ 3

Наверное, вопрос стиля, но если вы предпочитаете декораторов в тестах, @jamescastlefield answer может быть изменен на что-то вроде этого:

class MyClass:
    @property
    def last_transaction(self):
        # an expensive and complicated DB query here
        pass

class Test(unittest.TestCase):
    @mock.patch('MyClass.last_transaction', new_callable=PropertyMock)
    def test(mock_last_transaction):
        mock_last_transaction.return_value = Transaction()
        myclass = MyClass()
        print myclass.last_transaction
        mock_last_transaction.assert_called_once_with()

Ответ 4

Если вы не хотите проверять, был ли доступ к издеваемому свойству, вы можете просто его исправить с ожидаемым return_value.

with mock.patch(MyClass, 'last_transaction', Transaction()):
    ...

Ответ 5

Если объект, свойство которого вы хотите переопределить, является фиктивным объектом, вам не нужно использовать patch.

Вместо этого можно создать PropertyMock а затем переопределить свойство типа макета. Например, чтобы переопределить свойство mock_rows.pages для возврата (mock_page, mock_page,):

mock_page = mock.create_autospec(reader.ReadRowsPage)
# TODO: set up mock_page.
mock_pages = mock.PropertyMock(return_value=(mock_page, mock_page,))
type(mock_rows).pages = mock_pages