title: How to instruct a magic mock on how it should treat its arguments
body: <p>I've run into the following (edge?) case that I don't know how to handle properly. The general problem is that</p>
  
  <ul>
  <li>I have a function that I want to test</li>
  <li>in that function I call an external function with a generator comprehension as its argument</li>
  <li>in my tests, I mock the external function away</li>
  <li>now the prod code and the tested code differ: in prod, the generator is consumed, the mock doesn't do that</li>
  </ul>
  
  <hr>
  
  <p>Here is a reduced example of what it looks like in my codebase:</p>
  
  <pre class="lang-py prettyprint-override"><code>import itertools
  import random
  
  
  def my_side_effects():
      # imaginge itertools.accumulate was some expensive strange function
      # that consumes an iterable
      itertools.accumulate(random.randint(1, 5) for _ in range(10))
  
  
  def test_my_side_effects(mocker):
      my_mocked_func = mocker.patch('itertools.accumulate')
  
      my_side_effects()
  
      # make sure that side-effects took place. can't do much else.
      assert my_mocked_func.call_count == 1
  </code></pre>
  
  <p>The test runs just fine, and is good enough for all I care. But when I run <a href="https://coverage.readthedocs.io/en/coverage-5.0.4/" rel="nofollow noreferrer"><code>coverage</code></a> on the code, the situation that I described in the abstract becomes apparent:</p>
  
  <pre><code>----------- coverage: platform linux, python 3.8.0-final-0 -----------
  Name                                   Stmts   Miss Branch BrPart  Cover   Missing
  ----------------------------------------------------------------------------------
  [...]
  my_test_case.py                            5      0      2      1    86%   6-&gt;exit
  [...]
  ----------------------------------------------------------------------------------
  # something like this, the -&gt;exit part on the external call is the relevant part
  </code></pre>
  
  <p><a href="https://stackoverflow.com/questions/37304078/how-do-i-interpret-python-coverage-py-branch-coverage-results">Explanation of the <code>-&gt;exit</code> syntax in coverage.py.</a>
  Given that the comprehension could execute relevant business logic that I actually do want to run, the missed coverage is relevant. It's just calling <code>random.randint</code> here, but it <em>could</em> do anything.</p>
  
  <hr>
  
  <p>Workarounds:</p>
  
  <ol>
  <li>I can just use a list comprehension instead. The code is called and everybody is happy. Except me, who has to modify their backend in order to mollify tests.</li>
  <li>I can reach into the mock during the test, grab the call arg, and unroll it by hand. This will probably look godawful.</li>
  <li>I can monkeypatch the function instead of using a magicmock, something like <code>monkeypatch.setattr('itertools.accumulate', lambda x: [*x])</code> would be quite descriptive. But I would lose the ability to make call assertions like in my example.</li>
  </ol>
  
  <p>What I would consider a good solution would be something like this, which sadly doesn't exist:</p>
  
  <pre class="lang-py prettyprint-override"><code>def test_my_side_effects(mocker):
      my_mocked_func = mocker.patch('itertools.accumulate')
  
      # could also take "await", and assign treatments by keyword
      my_mocked_func.arg_treatment('unroll')  
  
      my_side_effects()
  
      # make sure that side-effects took place. can't do much else.
      assert my_mocked_func.call_count == 1
  </code></pre>