Mock property return value gets overridden when instantiating mock object
<h2>Background</h2>

<p>I'm trying to set up a test fixture for an application I'm writing in which one of my classes is replaced with a mock. I'm happy to leave most of the attributes of the mock class as the default <code>MagicMock</code> instances (where I'm only interested in making assertions about their usage), but the class also has a property that I want to provide a specific return value for.</p>

<p>For reference, this is the outline of the class I'm trying to patch:</p>

<pre><code>class CommunicationService(object):
    def __init__(self):
        self.__received_response = Subject()

    @property
    def received_response(self):
        return self.__received_response

    def establish_communication(self, hostname: str, port: int) -&gt; None:
        pass

    def send_request(self, request: str) -&gt; None:
        pass
</code></pre>

<h2>Problem</h2>

<p>The difficulty I'm having is that when I patch <code>CommunicationService</code>, I also try to set a <code>PropertyMock</code> for the <code>received_response</code> attribute that will return a specific value. When I instantiate this class in my production code, however, I'm finding that calls to <code>CommunicationService.received_response</code> are returning the default <code>MagicMock</code> instances instead of the specific value I want them to return.</p>

<p>During test setup, I do the following:</p>

<pre><code>context.mock_comms_exit_stack = ExitStack()
context.mock_comms = context.mock_comms_exit_stack.enter_context(
    patch('testcube.comms.CommunicationService', spec=True))

# Make 'received_response' observers subscribe to a mock subject.
context.mock_received_response_subject = Subject()
type(context.mock_comms).received_response = PropertyMock(return_value=context.mock_received_response_subject)

# Reload TestCube module to make it import the mock communications class.
reload_testcube_module(context)
</code></pre>

<p>In my production code (invoked after performing this setup):</p>

<pre><code># Establish communication with TestCube Web Service.
comms = CommunicationService()
comms.establish_communication(hostname, port)

# Wire plugins with communications service.
for plugin in context.command.plugins:
    plugin.on_response = comms.received_response
    plugin.request_generated.subscribe(comms.send_request)
</code></pre>

<p>I expect <code>comms.received_response</code> to be an instance of <code>Subject</code> (the return value of the property mock). However, instead I get the following: </p>

<pre><code>&lt;MagicMock name='CommunicationService().received_response' id='4580209944'&gt;
</code></pre>

<p>The problem seems to be that the mock property on the instance returned from the patch method works fine, but <em>mock properties get messed up when creating a new instance of the patched class</em>.</p>

<h2>SSCCE</h2>

<p>I believe that the snippet below captures the essence of this problem. If there's a way to modify the script below to make it so that <code>print(foo.bar)</code> returns <code>mock value</code>, then hopefully it'll show how I can resolve the problem in my actual code.</p>

<pre><code>from contextlib import ExitStack
from unittest.mock import patch, PropertyMock

class Foo:
    @property
    def bar(self):
        return 'real value'

exit_stack = ExitStack()
mock_foo = exit_stack.enter_context(patch('__main__.Foo', spec=True))
mock_bar = PropertyMock(return_value='mock value')
type(mock_foo).bar = mock_bar

print(mock_foo.bar) # 'mock value' (expected)

foo = Foo()
print(foo.bar) # &lt;MagicMock name='Foo().bar' id='4372262080'&gt; (unexpected - should be 'mock value')

exit_stack.close()
</code></pre>

<p>The following line:</p>

<pre><code>type(mock_foo).bar = mock_bar
</code></pre>

<p>mocks <code>mock_foo</code> which, at that point, is the return value of <code>enter_context</code>. If I understand <a href="https://docs.python.org/3/library/contextlib.html#contextlib.ExitStack.enter_context" rel="nofollow">the documentation</a> correctly it means you're now actually handling the result of <code>__enter__</code> of the return value of <code>patch('__main__.Foo', spec=True)</code>.</p>

<p>If you change that line to:</p>

<pre><code>type(Foo.return_value).bar = mock_bar
</code></pre>

<p>then you'll mock the property <code>bar</code> of instances of <code>Foo</code> (as the return value of calling a class is an instance). The second print statement will then print <code>mock value</code> as expected.</p>

python python-3.x mocking python-mock