我问如何使用 Python 3 在单元测试中模拟类属性。我尝试了以下方法,这对我遵循文档有意义,但它不起作用:
foo.py:
class Foo():
@property
def bar(self):
return 'foobar'
def test_foo_bar(mocker):
foo = Foo()
mocker.patch.object(foo, 'bar', new_callable=mocker.PropertyMock)
print(foo.bar)
我已经安装了
pytest
和 pytest_mock
并像这样运行测试:
pytest foo.py
我收到以下错误:
> setattr(self.target, self.attribute, new_attr)
E AttributeError: can't set attribute
/usr/lib/python3.5/unittest/mock.py:1312: AttributeError
我的期望是测试运行没有错误。
属性机制依赖于对象类上定义的属性属性。您无法在类的单个实例上创建“类似属性”的方法或属性(为了更好地理解,请阅读 Python 的描述符协议)
因此,您必须将补丁应用到您的类 - 您可以使用
with
语句,以便在测试后正确恢复类:
def test_foo_bar(mock):
foo = Foo()
with mock.patch(__name__ + "Foo.bar", new=mocker.PropertyMock)
print(foo.bar)
如果不需要额外的功能,可以直接返回值
from mock import patch
@patch('foo.Foo.bar', 'mocked_property_value')
def test_foo_bar():
foo = Foo()
print(foo.bar)
或者你可以通过调用函数来包装 MagicMocks
property
:
from mock import patch, MagicMock
@patch('foo.Foo.bar', property(MagicMock(return_value='mocked_property_value')))
def test_foo_bar():
foo = Foo()
print(foo.bar)
更简单的方法是利用PropertyMock和MagicMock;以下效果很好:
def test_foo_bar():
mockedFoo: MagicMock = MagicMock(spec=Foo)
type(mockedFoo).bar = PropertyMock(return_value='Mocked foobar')
print(mockedFoo.bar)