Я использую удваивает вместе с pytest для модульного тестирования некоторого кода Python 2.7.
Допустим, у меня есть такой класс, как:
class Foo(object):
def bar(self, value):
pass
И у меня есть некоторый код, в который вставляется экземпляр Foo
, и который вызывает method
:
def do_bar(foo):
foo.bar(22)
Я знаю, как создать ожидание
def test_doing_bar_sets_bar_to_22():
foo = Foo()
expect(foo).bar(22)
do_bar(foo)
Но мне интересно, как создать ожидание для установщика свойства, определенного с помощью декоратора @property
:
class Foo(object):
def bar(self):
pass
@property
def bee(self):
pass
@bee.setter
def bee(self, value):
pass
def do_bee(foo):
foo.bee = 22
Чтобы сделать эту работу:
def test_doing_bee_sets_bee_to_22():
foo = Foo()
# Something like expect(foo.bee).setter(22)
# I tried: expect(foo.__class__.bee).setter(foo, 22)
do_bee(foo)
Я знаю, что мог бы просто создать класс со свойством bee
, которое захватывает значение и передает этот экземпляр методу do_bee
, но если возможно разрешить его с помощью подхода expect
, я предпочитаю его за симметрию с остальным кодом и выразительность.
Можно ли сделать это с double ?
ОБНОВЛЕНИЕ 2019-01-24
Я провел некоторое исследование в исходном коде парных символов:
https://github.com/uber/doubles/blob/master/doubles/proxy_property.py
https://github.com/uber/doubles/blob/master/doubles/proxy_method.py
Я считаю, что реализация ProxyProperty не позволит создавать допуски / ожидания, когда свойство имеет установщик. В частности, я считаю, что __set__
должен быть реализован, но я не совсем понимаю , как должны работать допуски / ожидания в отношении свойств (с точки зрения дизайна).
Я мог бы заставить его работать, изменив реализацию ProxyProperty
на:
class ProxyProperty(object):
def __init__(self, name, original):
self._name = name
self._original = original
def __get__(self, obj, objtype=None):
return obj.__dict__.get(self._name, self._original.__get__(obj, objtype))
def __set__(self, obj, value):
obj.__dict__[self._name] = value
(Также в proxy_method.ProxyMethod._hijack_target
я удаляю self._target.obj.__dict__[double_name(self._method_name)] = self
, так как он больше не имеет смысла для меня после моих изменений).
С этими изменениями я могу написать:
def test_doing_bee_sets_bee_to_22():
foo = Foo()
allow(foo).bee
do_bee(foo)
assert foo.bee == 22
Однако я бы предпочел иметь такой механизм, как with_args (), потому что он позволил бы создать несколько ожиданий, если, например, doo_bee установит foo.bee несколько раз.
ОБНОВЛЕНИЕ 2019-02-23
Я открыл проблему на их странице Github, и они недавно пометили ее как ошибку.