首页 > 解决方案 > 使 PropertyMock 包装现有属性 - Python

问题描述

我想测试在调用 Python 方法时实例变量是否“设置”为特定值(即多次)。

用 a 替换实例变量PropertyMock允许我查看mock_calls并验证属性设置的值。但是,PropertyMock它的行为不像普通变量。当您在其上设置一个值并尝试读取它时,您会返回另一个 Mock。有没有办法取回价值?

这是一个人为的例子:

import time
from unittest.mock import PropertyMock, call


class Machine:

    def __init__(self):
        self.mode = "idle"

    def start(self):

        # Update mode
        self.mode = "running"

        # Do some work, e.g. drive a motor for 0.5 sec
        time.sleep(0.5)

        # Restore mode
        if self.mode == "running":         # Should always be True, but isn't when using PropertyMock
            self.mode = "idle"


class Test_Machine:

    def test(self):

        # Create a machine
        real_machine = Machine()

        # Mock the 'mode' property
        mocked_property = PropertyMock()
        type(real_machine).mode = mocked_property

        # Call the method to test
        real_machine.start()

        print(mocked_property.mock_calls)                         # [call('running'), call(), call().__eq__('running')]
        assert call("running") == mocked_property.mock_calls[0]   # Success
        assert call("idle") == mocked_property.mock_calls[-1]     # Fails here


标签: pythonunit-testingmockingpython-unittest

解决方案


我敢肯定有更好的方法来做到这一点,但如果你只是对属性设置器的调用感兴趣,并且希望 getter 表现得像原始属性,你可以重写PropertyMock以表现得像这样:

class MyPropertyMock(PropertyMock):
    def __init__(self, value=None):
        super().__init__()
        self.value = value

    def __get__(self, obj, obj_type):
        return self.value  # the mock will not register these calls

    def __set__(self, obj, val):
        self.value = val
        super().__set__(obj, val)  # ensure the mock behavior in the setter


class Test_Machine:
    def test(self):
        real_machine = Machine()
        mocked_property = MyPropertyMock(real_machine.value)
        Machine.mode = mocked_property

        real_machine.start()

        print(mocked_property.mock_calls)  # [call('running'), call('idle')]
        ...

推荐阅读