Заставить PropertyMock обернуть существующее свойство - Python - PullRequest
1 голос
/ 28 мая 2020

Я хочу проверить, что переменная экземпляра «установлена» на указание c значений (т.е. несколько раз) при вызове метода 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


1 Ответ

0 голосов
/ 28 мая 2020

Я уверен, что есть лучший способ сделать это, но если вас просто интересуют вызовы установщика свойств и вы хотите, чтобы получатель вел себя как исходное свойство, вы можете переопределить 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')]
        ...
...