我正在将doubles与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
装饰器定义的属性的setter上创建期望:
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
方法,但是如果可以通过{{1}来解决它}方法,我更喜欢它与其他代码的对称性和表现力。
是否可以通过 doubles 做到这一点?
更新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实现将不允许创建配额/期望。特别是,我认为应该实施expect
,但我并不完全理解(从设计的角度来看)财产津贴/期望的工作原理。
我可以通过将__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
但是我更喜欢使用诸如with_args()之类的机制,因为如果例如doo_bee多次设置foo.bee,它将允许创建多个期望。
更新2019-02-23 我在其Github页面中打开了一个issue,他们最近将其标记为错误。