title: How can I mock patch a class used in an isinstance test?
body: <p>I want to test the function <code>is_myclass</code>. Please help me understand how to write a successful test.</p>
  
  <pre><code>def is_myclass(obj):
      """This absurd stub is a simplified version of the production code."""
      isinstance(obj, MyClass)
      MyClass()
  </code></pre>
  
  <p><strong>Docs</strong></p>
  
  <p>The Python Docs for unittest.mock illustrate three ways of addressing the <code>isinstance</code> problem:</p>
  
  <ul>
  <li>Set the <code>spec</code> parameter to the real class. </li>
  <li>Assign the real class to the <code>__class__</code> attribute. </li>
  <li>Use <code>spec</code> in the patch of the real class.</li>
  </ul>
  
  <blockquote>
    <p><code>__class__</code></p>
    
    <p>Normally the <code>__class__</code> attribute of an object will return its type. For a mock object with a spec, <code>__class__</code> returns the spec class instead. This allows mock objects to pass isinstance() tests for the object they are replacing / masquerading as:</p>
  
  <pre><code>&gt;&gt;&gt; mock = Mock(spec=3)
  &gt;&gt;&gt; isinstance(mock, int)
  True
  </code></pre>
    
    <p><code>__class__</code> is assignable to, this allows a mock to pass an <code>isinstance()</code> check without forcing you to use a spec:</p>
  
  <pre><code>&gt;&gt;&gt; mock = Mock()
  &gt;&gt;&gt; mock.__class__ = dict
  &gt;&gt;&gt; isinstance(mock, dict)
  True
  </code></pre>
    
    <p>[...]</p>
    
    <p>If you use <code>spec</code> or <code>spec_set</code> and <code>patch()</code> is replacing a class, then the return value of the created mock will have the same spec.</p>
  
  <pre><code>&gt;&gt;&gt; Original = Class
  &gt;&gt;&gt; patcher = patch('__main__.Class', spec=True)
  &gt;&gt;&gt; MockClass = patcher.start()
  &gt;&gt;&gt; instance = MockClass()
  &gt;&gt;&gt; assert isinstance(instance, Original)
  &gt;&gt;&gt; patcher.stop()
  </code></pre>
  </blockquote>
  
  <p><strong>Tests</strong></p>
  
  <p>I have written five tests each of which attempts firstly to reproduce each of the three solutions and secondly to carry out a realistic test of the target code. The typical pattern is  <code>assert isinstance</code>  followed by a call to <code>is_myclass</code>.</p>
  
  <p>All tests fail.</p>
  
  <p><strong>Test 1</strong></p>
  
  <p>This is a close copy of the example provided in the docs for the use of <code>spec</code>. It
  differs from the docs by using <code>spec=&lt;class&gt;</code> instead of <code>spec=&lt;instance&gt;</code>. It passes
  a local assert test but the call to <code>is_myclass</code> fails because <code>MyClass</code> is not mocked.</p>
  
  <p>This is equivalent to Michele d’Amico’s answer to the similar question in <a href="https://stackoverflow.com/questions/11146725/isinstance-and-mocking">isinstance and Mocking </a>.</p>
  
  <p><strong>Test 2</strong></p>
  
  <p>This is the patched equivalent of test 1. The <code>spec</code> argument fails to set the <code>__class__</code> of the mocked MyClass and the test fails the local <code>assert isinstance</code>.</p>
  
  <p><strong>Test 3</strong></p>
  
  <p>This is a close copy of the example provided in the docs for the use of <code>__class__</code>. It passes
  a local assert test but the call to <code>is_myclass</code> fails because <code>MyClass</code> is not mocked.</p>
  
  <p><strong>Test 4</strong></p>
  
  <p>This is the patched equivalent of test 3. The assignment to <code>__class__</code> does set the <code>__class__</code> of the mocked <code>MyClass</code> but this does not change its type and so the test fails the local <code>assert isinstance</code>.</p>
  
  <p><strong>Test 5</strong></p>
  
  <p>This is a close copy of the use of <code>spec</code> in a call to patch. It passes the local assert test but only by virtue of accessing a local copy of MyClass. Since this local variable is not used within <code>is_myclass</code> the call fails.</p>
  
  <p><strong>Code</strong></p>
  
  <p><em>This code was written as a stand alone test module intended to be run in the PyCharm IDE. You may need to modify it to run in other test environments.</em></p>
  
  <p>module temp2.py</p>
  
  <pre><code>import unittest
  import unittest.mock as mock
  
  
  class WrongCodeTested(Exception):
      pass
  
  
  class MyClass:
      def __init__(self):
          """This is a simplified version of a production class which must be mocked for unittesting."""
          raise WrongCodeTested('Testing code in MyClass.__init__')
  
  
  def is_myclass(obj):
      """This absurd stub is a simplified version of the production code."""
      isinstance(obj, MyClass)
      MyClass()
  
  
  class ExamplesFromDocs(unittest.TestCase):
      def test_1_spec(self):
          obj = mock.Mock(spec=MyClass)
          print(type(MyClass))  # &lt;class 'type'&gt;
          assert isinstance(obj, MyClass)  # Local assert test passes
          is_myclass(obj)  # Fail: MyClass instantiated
  
  
      def test_2_spec_patch(self):
          with mock.patch('temp2.MyClass', spec=True) as mock_myclass:
              obj = mock_myclass()
              print(type(mock_myclass))  # &lt;class 'unittest.mock.MagicMock'&gt;
              print(type(MyClass))  # &lt;class 'unittest.mock.MagicMock'&gt;
              assert isinstance(obj, MyClass)  # Local assert test fails
  
      def test_3__class__(self):
          obj = mock.Mock()
          obj.__class__ = MyClass
          print(type(MyClass))  # &lt;class 'type'&gt;
          isinstance(obj, MyClass)  # Local assert test passes
          is_myclass(obj)  # Fail: MyClass instantiated
  
      def test_4__class__patch(self):
          Original = MyClass
          with mock.patch('temp2.MyClass') as mock_myclass:
              mock_myclass.__class__ = Original
              obj = mock_myclass()
              obj.__class__ = Original
              print(MyClass.__class__)  # &lt;class 'temp2.MyClass'&gt;
              print(type(MyClass))  # &lt;class 'unittest.mock.MagicMock'&gt;
              assert isinstance(obj, MyClass)  # Local assert test fails
  
      def test_5_patch_with_spec(self):
          Original = MyClass
          p = mock.patch('temp2.MyClass', spec=True)
          MockMyClass = p.start()
          obj = MockMyClass()
          print(type(Original))  # &lt;class 'type'&gt;
          print(type(MyClass))  # &lt;class 'unittest.mock.MagicMock'&gt;
          print(type(MockMyClass))  # &lt;class 'unittest.mock.MagicMock'&gt;
          assert isinstance(obj, Original)  # Local assert test passes
          is_myclass(obj)  # Fail: Bad type for MyClass
  </code></pre>