python patch with side_effect on Object's method is not called with self
<p>I encounter a surprising behaviour of the side_effect parameter in patch.object where the function replacing the original does not receive <code>self</code></p>

<pre class="lang-py prettyprint-override"><code>class Animal():
    def __init__(self):
        self.noise = 'Woof'

    def make_noise(self):
        return self.noise

def loud(self):
    return self.noise.upper() + '!!'


from unittest.mock import patch

dog = Animal()
dog.make_noise()
with patch.object(Animal, 'make_noise', side_effect=loud):
    dog.make_noise()
</code></pre>

<p>This give:</p>

<pre><code>Traceback (most recent call last):
  File "&lt;stdin&gt;", line 2, in &lt;module&gt;
  File "/lustre/home/production/Applications/python/python-3.4.4/lib/python3.4/unittest/mock.py", line 902, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/lustre/home/production/Applications/python/python-3.4.4/lib/python3.4/unittest/mock.py", line 968, in _mock_call
    ret_val = effect(*args, **kwargs)
TypeError: loud() missing 1 required positional argument: 'self'
</code></pre>

<p>If I change the <code>loud</code> function to  </p>

<pre><code>def loud(*args, **kwargs):
    print(args)
    print(kwargs)
</code></pre>

<p>I get the following output:</p>

<pre><code>()
{}
</code></pre>

<p>Is there a way to replace a function from an object and still receive self?</p>

<p><code>self</code> is only supplied for <em>bound methods</em> (because functions are <a href="https://docs.python.org/3/howto/descriptor.html" rel="nofollow">descriptors</a>). A <code>Mock</code> object is not such a method, and the <code>side_effect</code> function is not bound, so <code>self</code> is indeed not going to be passed in.</p>

<p>If you <em>must</em> have access the instance in a <code>side_effect</code> object, you'll have to patch the function on the class with an actual function:</p>

<pre><code>with patch.object(Animal, 'make_noise', new=loud):
</code></pre>

<p>Now <code>make_noise</code> is replaced by the <code>loud</code> function on the <code>Animal</code> class, so it'll be bound:</p>

<pre><code>&gt;&gt;&gt; with patch.object(Animal, 'make_noise', new=loud):
...     dog.make_noise()
...
'WOOF!!'
</code></pre>

<p>The alternative is to set <code>autospec=True</code>, at which point <code>mock</code> will use a real function to mock out <code>make_noise()</code>:</p>

<pre><code>&gt;&gt;&gt; with patch.object(Animal, 'make_noise', autospec=True, side_effect=loud):
...     dog.make_noise()
...
'WOOF!!'
</code></pre>

<p>Also see the <a href="https://docs.python.org/3/library/unittest.mock-examples.html#mocking-unbound-methods" rel="nofollow"><em>Mocking Unbound Methods</em> section</a> in the mock <em>getting started</em> section.</p>

python unit-testing mocking