【问题标题】:Making PropertyMock wrap an existing property - Python使 PropertyMock 包装现有属性 - Python
【发布时间】:2020-05-28 00:35:34
【问题描述】:

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

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


【问题讨论】:

    标签: python unit-testing mocking python-unittest


    【解决方案1】:

    我确信有更好的方法来做到这一点,但如果您只是对属性设置器的调用感兴趣,并且希望 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')]
            ...
    

    【讨论】:

      猜你喜欢
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-03
      • 2017-10-23
      • 2014-06-24
      相关资源
      最近更新 更多