1

正如unittest.mock 文档指出的那样:

由于模拟属性的存储方式,您不能直接将 PropertyMock 附加到模拟对象。相反,您可以将其附加到模拟类型对象

但是,我遇到了想在单个测试中模拟多个类实例上的多个属性值的情况。

例如,假设我有一个TimeSlot带有availability属性的类:

class TimeSlot:
    @property
    def availability(self):
        # Run a complex DB query to determine availability

...而且我有一个帮助类,它按以下方式对TimeSlot实例列表进行排序availability

from unittest.mock import Mock

from app.helpers import sort_slots
from app.models import TimeSlot


def test_sort_slots_reorders_by_descending_availability():
    slot_a = TimeSlot()
    slot_a.availability = Mock(return_value=0.1) # BOOM!

    slot_b = TimeSlot()
    slot_b.availability = Mock(return_value=0.2)

    slots = [slot_a, slot_b]

    assert sort_slots(slots) == [slot_b, slot_a]

当我尝试将 Mock(或 PropertyMock)分配给属性时,运行此测试会引发错误availability

AttributeError: can't set attribute

有没有办法模拟Python 类的每个实例的属性返回值?

如果没有,我应该以不同的方式来编写这样的单元测试吗?

谢谢!

4

2 回答 2

3

availability属性是在TimeSlot类上定义的,而不是在实例上定义的,因此您需要用类级别的东西替换它。在这个例子中,我用一个类属性替换它,然后用实例属性覆盖它。

from unittest.mock import patch

class TimeSlot:
    @property
    def availability(self):
        return 0.0

slot1 = TimeSlot()
slot2 = TimeSlot()
with patch('__main__.TimeSlot.availability', 0.0):
    slot1.availability = 0.1
    slot2.availability = 0.2

    assert slot1.availability == 0.1
    assert slot2.availability == 0.2

with块结束时,原始availability属性将被放回原处。

于 2019-09-01T22:36:19.637 回答
0

您应该嘲笑 TimeSlot 对象本身。这允许更改availability属性的行为方式。

于 2019-08-30T19:51:29.623 回答