如何模拟属性

问题描述 投票:0回答:3

我问如何使用 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 python-3.x pytest python-unittest python-mock
3个回答
25
投票

属性机制依赖于对象类上定义的属性属性。您无法在类的单个实例上创建“类似属性”的方法或属性(为了更好地理解,请阅读 Python 的描述符协议

因此,您必须将补丁应用到您的类 - 您可以使用

with
语句,以便在测试后正确恢复类:

def test_foo_bar(mock):
    foo = Foo()
    with mock.patch(__name__ + "Foo.bar", new=mocker.PropertyMock)
        print(foo.bar)

3
投票

如果不需要额外的功能,可以直接返回值

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)

0
投票

更简单的方法是利用PropertyMock和MagicMock;以下效果很好:

def test_foo_bar():

    mockedFoo: MagicMock = MagicMock(spec=Foo)

    type(mockedFoo).bar = PropertyMock(return_value='Mocked foobar')

    print(mockedFoo.bar)
© www.soinside.com 2019 - 2024. All rights reserved.