If you’ve ever used Mock (or the built-in mock in python 3), you’ll know how powerful of a tool it can be toward making unit testing on functions modifying state sane. Mocks in Python are effectively a probe that you can send into a deep, dark function:

<span></span><span class="kn">import</span> <span class="nn">mock</span>

<span class="k">def</span> <span class="nf">test_write_hello_world</span><span class="p">():</span>
    <span class="n">my_filehandle</span> <span class="o">=</span> <span class="n">mock</span><span class="o">.</span><span class="n">Mock</span><span class="p">()</span>
    <span class="n">write_hello_world_to_handle</span><span class="p">(</span><span class="n">my_filehandle</span><span class="p">)</span>
    <span class="n">my_filehandle</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">assert_called_with</span><span class="p">(</span><span class="s2">"hello world"</span><span class="p">)</span>

You can send in a fake object, have it experience what it’s like to be a real object, and you can ask it questions about what is was like.

The above example doesn’t really test a lot, but for more complex cases, it can be a lifesaver: you know exactly what was called and what wasn’t, and if your object modifies some real world state that you don’t want to (such as a database), it prevents you from performing dangerous operations.

Another well-known feature of the mock module is patch: a function that gives you the ability to replace any object in python (in any module) with a mocked object. An example usage is like this:

<span></span><span class="kn">import</span> <span class="nn">mock</span>

<span class="k">def</span> <span class="nf">test_linux</span><span class="p">():</span>
    <span class="k">with</span> <span class="n">mock</span><span class="o">.</span><span class="n">patch</span><span class="p">(</span><span class="s1">'platform.system'</span><span class="p">)</span> <span class="k">as</span> <span class="n">system</span><span class="p">:</span>
        <span class="n">system</span><span class="o">.</span><span class="n">return_value</span> <span class="o">=</span> <span class="s1">'Linux'</span>
        <span class="kn">import</span> <span class="nn">platform</span>
        <span class="k">assert</span> <span class="n">platform</span><span class="o">.</span><span class="n">system</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'Linux'</span>

Patch is powerful: it actually lets you replace modules, functions, and values, even if they’re not imported in the current context!

But just because a tool is powerful, doesn’t mean you should use it. In reality, patch should be a last resort: you should only use it if there’s no other way to test your code.

But why? Patch is basically making mock even more flexible: you can literally mock anything you are aware of exists. There’s a couple glaring issues:

It’s not foolproof #

Let’s say I have a couple files like this:

<span></span><span class="c1"># mock_test.py</span>

<span class="kn">from</span> <span class="nn">mymodule</span> <span class="kn">import</span> <span class="n">is_my_os</span>
<span class="k">try</span><span class="p">:</span>
    <span class="kn">from</span> <span class="nn">unittest</span> <span class="kn">import</span> <span class="n">mock</span>  <span class="c1"># py3</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
    <span class="kn">import</span> <span class="nn">mock</span>  <span class="c1"># py2</span>

<span class="k">with</span> <span class="n">mock</span><span class="o">.</span><span class="n">patch</span><span class="p">(</span><span class="s1">'platform.system'</span><span class="p">,</span> <span class="n">return_value</span><span class="o">=</span><span class="s2">"my os"</span><span class="p">):</span>
    <span class="k">assert</span> <span class="n">is_my_os</span><span class="p">()</span>











<span></span><span class="c1"># mymodule.py</span>
<span class="kn">from</span> <span class="nn">platform</span> <span class="kn">import</span> <span class="n">system</span>

<span class="k">def</span> <span class="nf">is_my_os</span><span class="p">():</span>
    <span class="k">return</span> <span class="n">system</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"my os"</span>

Now patch is patching the platform.system function, so this should pass. Let’s try it:

<span></span><span class="err">$</span> <span class="n">python</span> <span class="n">mock_test</span><span class="o">.</span><span class="n">py</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
  <span class="n">File</span> <span class="s2">"./bin/python"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">42</span><span class="p">,</span> <span class="ow">in</span> <span class="o"><</span><span class="n">module</span><span class="o">></span>
    <span class="n">exec</span><span class="p">(</span><span class="nb">compile</span><span class="p">(</span><span class="n">__file__f</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span> <span class="vm">__file__</span><span class="p">,</span> <span class="s2">"exec"</span><span class="p">))</span>
  <span class="n">File</span> <span class="s2">"/Users/tsutsumi/sandbox/mock_test.py"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">11</span><span class="p">,</span> <span class="ow">in</span> <span class="o"><</span><span class="n">module</span><span class="o">></span>
<span class="k">assert</span> <span class="n">is_my_os</span><span class="p">()</span>
    <span class="ne">AssertionError</span>

That’s not what we expected! So what happened here?

Internally, every python module contains it’s own scope. Every import, method declaration, and variable declaration, and expression modifies that scope in someway. So when you import anything, you are actually adding in a reference to that object into the global scope. So by the time we actually mock ‘platform.system’, the module’s ‘platform’ already contains a reference to the ‘system’ function:

<span></span><span class="err">$</span> <span class="n">python</span>
<span class="o">>>></span> <span class="kn">import</span> <span class="nn">platform</span>
<span class="o">>>></span> <span class="kn">from</span> <span class="nn">platform</span> <span class="kn">import</span> <span class="n">system</span>
<span class="o">>>></span> <span class="kn">import</span> <span class="nn">mock</span>
<span class="o">>>></span> <span class="k">with</span> <span class="n">mock</span><span class="o">.</span><span class="n">patch</span><span class="p">(</span><span class="s1">'platform.system'</span><span class="p">)</span> <span class="k">as</span> <span class="n">mock_system</span><span class="p">:</span>
<span class="o">...</span>     <span class="nb">print</span><span class="p">(</span><span class="n">mock_system</span><span class="p">)</span>
<span class="o">...</span>     <span class="nb">print</span><span class="p">(</span><span class="n">system</span><span class="p">)</span>
<span class="o">...</span>     <span class="nb">print</span><span class="p">(</span><span class="n">platform</span><span class="o">.</span><span class="n">system</span><span class="p">)</span>
<span class="o">...</span>
<span class="o"><</span><span class="n">MagicMock</span> <span class="n">name</span><span class="o">=</span><span class="s1">'system'</span> <span class="nb">id</span><span class="o">=</span><span class="s1">'4307612752'</span><span class="o">></span>
<span class="o"><</span><span class="n">function</span> <span class="n">system</span> <span class="n">at</span> <span class="mh">0x100bf9c80</span><span class="o">></span>
<span class="o"><</span><span class="n">MagicMock</span> <span class="n">name</span><span class="o">=</span><span class="s1">'system'</span> <span class="nb">id</span><span class="o">=</span><span class="s1">'4307612752'</span><span class="o">></span>
<span class="o">>>></span>

So even if you do patch a method, you won’t necessarily patch all the uses of that method, depending on how they’re imported in. This means your patching must directly match how the object you want to mock is imported into the code to test.

For example, we can fix the mock_test.py file above by changing the patch:

<span></span><span class="c1"># mock_test.py</span>

<span class="kn">from</span> <span class="nn">mymodule</span> <span class="kn">import</span> <span class="n">is_my_os</span>
<span class="k">try</span><span class="p">:</span>
    <span class="kn">from</span> <span class="nn">unittest</span> <span class="kn">import</span> <span class="n">mock</span>  <span class="c1"># py3</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
    <span class="kn">import</span> <span class="nn">mock</span>  <span class="c1"># py2</span>

<span class="k">with</span> <span class="n">mock</span><span class="o">.</span><span class="n">patch</span><span class="p">(</span><span class="s1">'mymodule.system'</span><span class="p">,</span> <span class="n">return_value</span><span class="o">=</span><span class="s2">"my os"</span><span class="p">):</span>
    <span class="k">assert</span> <span class="n">is_my_os</span><span class="p">()</span>

So in order to use a patch effectively, you have to be aware of exact semantics by which a method is both imported an invoked. And this leads up to the ultimate problem with patch:

Really tightly coupling tests with implementation #

Patching in general, regardless of the implementation, tightly couples your test code and your regular code beyond the typical bounds of unit testing. Once you get patching involved, you have to not only be conscious of the effect of your code, but also it’s implementation. Modifying the internal code of the method also requires modifying the test code. If your unit tests change, the actual functionality it’s testing is also changed: you’re no longer guaranteed that your code is identical because the same tests pass: because modifying your code requires you to change your test code.

Ultimately however, we don’t live in an ideal world. Times will come when you have to test code that is hard to refactor into a method that works with only mocks or actual objects. But with code you control, it’s almost completely avoidable.

So how do we avoid patching? #

Patching is the result of coupled complex state, relying on multiple global variables. We can remedy this by doing the exact opposite:

  • decouple complex state

  • don’t rely on global variables

Let’s take a look at some practices to help with this:

Don’t use global variables #

for example, let’s look at an object that creates a persistent db connection based on configuration parameters:

<span></span><span class="n">db_connection</span> <span class="o">=</span> <span class="n">db_connect</span><span class="p">(</span><span class="n">DB_URL</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">MyObject</span><span class="p">:</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>

    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">db_connection</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">to_dict</span><span class="p">())</span>

    <span class="k">def</span> <span class="nf">to_dict</span><span class="p">():</span>
        <span class="k">return</span> <span class="p">{</span> <span class="s1">'name'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="p">}</span>

To test this object’s save method, you would have either patch the db_connection object, or replace the DB_URL to reflect a test database. Either method is an extra step from testing what you really want on just the save method: the db method is called, and is passed the dictionary representation of the object.

You can accomplish this without patch by passing in objects as you need them: by explicitly passing them in, it makes it really easy to mock:

<span></span><span class="k">class</span> <span class="nc">MyObject</span><span class="p">:</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>

    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">db</span><span class="p">):</span>
        <span class="n">db</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">to_dict</span><span class="p">())</span>

    <span class="k">def</span> <span class="nf">to_dict</span><span class="p">():</span>
        <span class="k">return</span> <span class="p">{</span> <span class="s1">'name'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="p">}</span>

 <span class="k">def</span> <span class="nf">test_myobject_save</span><span class="p">():</span>
     <span class="kn">import</span> <span class="nn">mock</span>
     <span class="n">my_object</span> <span class="o">=</span> <span class="n">MyObject</span><span class="p">(</span><span class="s2">"foo"</span><span class="p">)</span>
     <span class="n">db</span> <span class="o">=</span> <span class="n">mock</span><span class="o">.</span><span class="n">Mock</span><span class="p">()</span>
     <span class="n">my_object</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">db</span><span class="p">)</span>
     <span class="k">assert</span> <span class="n">db</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">assert_called_with</span><span class="p">({</span>
         <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'foo'</span>
     <span class="p">})</span>

Decouple complex state #

Complex state coupling occurs when you attempt to hide a lot of the difficulty with creating objects from a user. Using the database above, as an example:

<span></span><span class="k">class</span> <span class="nc">MyObject</span><span class="p">:</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">db_url</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db_connection</span><span class="p">(</span><span class="n">db_url</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>

    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">to_dict</span><span class="p">())</span>

    <span class="k">def</span> <span class="nf">to_dict</span><span class="p">():</span>
        <span class="k">return</span> <span class="p">{</span> <span class="s1">'name'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="p">}</span>

Now the only way to actually test this save method (aside from a full stack test) is to mock the db_connection method. It wouldn’t work to assign the db attribute afterward (my_object._db = Mock()) because this would mean that the objects was already instantiated: your db connection already exists, creating extra overhead you won’t used.

Instead of trying to hide the complex state from the user of your class, let them actually choose the db object to pass in:

<span></span><span class="k">class</span> <span class="nc">MyObject</span><span class="p">:</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">db</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>

    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">to_dict</span><span class="p">())</span>

    <span class="k">def</span> <span class="nf">to_dict</span><span class="p">():</span>
        <span class="k">return</span> <span class="p">{</span> <span class="s1">'name'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="p">}</span>

 <span class="k">def</span> <span class="nf">test_myobject_save</span><span class="p">():</span>
     <span class="kn">import</span> <span class="nn">mock</span>
     <span class="n">db</span> <span class="o">=</span> <span class="n">mock</span><span class="o">.</span><span class="n">Mock</span><span class="p">()</span>
     <span class="n">my_object</span> <span class="o">=</span> <span class="n">MyObject</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">"foo"</span><span class="p">)</span>
     <span class="n">my_object</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
     <span class="k">assert</span> <span class="n">db</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">assert_called_with</span><span class="p">({</span>
         <span class="s1">'name'</span><span class="p">:</span> <span class="s1">'foo'</span>
     <span class="p">})</span>

This not only allows us to test operations on complex objects, but also makes the class more flexible as well (e.g. compatible with more db objects than just the one that db_connection returns)

Final thoughts #

Once again, patch exists for a reason. It’s almost like a magic wand that allows you to test otherwise untestable code. But this magic wand comes with making your life harder the more you use it.

So all in all: beware the dangers of patching.