Статьи

Еще один подход к насмешливым свойствам в Python

смайлик: вафля mock — это библиотека для тестирования на Python. Это позволяет заменять части тестируемой системы фиктивными объектами. Главной особенностью издеваться является то , что он прост в использовании, но издеваться также делает возможным более сложные сценарии насмешливые.

Такова моя философия проектирования API: простые вещи должны быть простыми, но сложные должны быть возможными .

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

Свойства в Python являются дескрипторами . Когда они выбираются из класса объекта, они запускают код, который затем выполняется. Код, который выполняется, является методом, который вы обернули как средство получения свойства.

Обратите внимание, что существует специальное правило для поиска атрибутов в определенных типах дескрипторов, которые включают свойства. Даже если атрибут экземпляра существует, атрибут класса все равно будет использоваться вместо него. Это исключение из обычного правила поиска атрибутов, когда атрибуты экземпляра выбираются предпочтительнее атрибутов класса. Это важно, потому что это означает, что когда вы хотите смоделировать свойство, вы должны сделать это в классе и не можете просто прикрепить атрибут к объекту.

Если вы используете mock 0.7 с его поддержкой магических методов , мы можем исправить имя свойства и добавить метод __get__ к нашему mock. Наличие метода __get__ делает его дескриптором, поэтому мы можем использовать его как свойство:

>>> from mock import Mock, patch
>>> class Foo(object):
...    @property
...    def fish(self):
...      return 'fish'
...
>>> with patch.object(Foo, 'fish') as mock_fish:
...   mock_fish.__get__ = Mock(return_value='mocked fish')
...   foo = Foo()
...   print foo.fish
...
mocked fish
>>> mock_fish.__get__.assert_called_with(mock_fish, foo, Foo)

В этом примере mock_fish заменяет свойство, а mock вместо __get__ становится методом получателя. Поскольку мы исправляем класс, это влияет на все экземпляры Foo .

Нет смысла использовать MagicMock для этого. MagicMock обычно упрощает использование методов протокола Python, предварительно настраивая их. Как вы можете видеть из приведенного выше примера, насмешливый __get__ будет поддерживаться , но он не подключен по умолчанию. Это не было бы полезно , если бы насмехаясь любойметод в классе заменил его на макет, который действовал как дескриптор, поэтому, если вы хотите, чтобы макет вел себя как дескриптор, вам нужно самостоятельно настроить __get__ , __set__ и __delete__ .

Вот альтернативный подход, который работает со всеми последними версиями mock:

>>> from mock import Mock, patch
>>> class PropertyMock(Mock):
...   def __get__(self, instance, owner):
...     return self()
...
>>> prop_mock = PropertyMock()
>>> with patch.object(Foo, 'fish', prop_mock):
...   foo = Foo()
...   prop_mock.return_value = 'mocked fish'
...   print foo.fish
...
mocked fish
>>> prop_mock.assert_called_with()

В качестве дополнительного бонуса оба этих примера работают, даже если экземпляр Foo создается вне блока исправлений . До тех пор, пока код, использующий свойство, выполняется, пока исправление установлено, поиск атрибутов найдет нашу смоделированную версию. источник: http://www.voidspace.org.uk/python/weblog/arch_d7_2011_06_04.shtml