title: Can mock automatically instantiate mock objects?
body: <p>I'm writing tests for the class <code>OnlineService</code> which instantiates a class of type <code>api.API</code>, which in turn instantiates a class of type <code>api.Resource</code>. The method I'm testing in this example is <code>initialize</code> which tests connectivity with the remote service, by issuing a <code>GET</code> request to a <code>Ping</code> resource in the remote API.</p>
  
  <p>I'm currently patching these objects to be mocks using the following code, but it still looks a bit verbose to me.</p>
  
  <pre><code>@patch('api.Resource')
  @patch('api.API')
  def test_initialize(self, api_mock, resource_mock):
      api_instance = api_mock.return_value
      api_instance.Ping = resource_mock.return_value # is this step really necessary?
      api_instance.Ping.get.side_effect = [None, HTTPError()]
  
      service = OnlineService()
  
      service.initialize()
      assert service.connected is True
  
      service.initialize()
      assert service.connected is False
  </code></pre>
  
  <p>Do I really have to assign a <code>Resource</code> mock instance to the property of another mock instance manually? Perhaps there is some feature in the <code>mock</code> package that can do this for me?</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I've split up the test in two and also attached the relevant code from the <code>OnlineService</code> that is under test. Here is the <code>OnlineService</code> class:</p>
  
  <pre><code>class OnlineService(object):
      def __init__(self):
          self.webservice_url = u''
          self.verify_ssl = True
          self.connected = False
  
      def initialize(self, webservice_url, verify_ssl, connectivity_check_timeout):
          self.webservice_url = webservice_url
          self.verify_ssl = verify_ssl
          self.connected = self.can_connect_to_api(connectivity_check_timeout)
  
      def can_connect_to_api(self, connectivity_check_timeout):
          api_instance = api.API(url=self.webservice_url, verify_ssl=self.verify_ssl, timeout=connectivity_check_timeout)
          try:
              # api_instance.Ping of type api.Resource was instantiated in api.API()
              api_instance.Ping.get()
              return True
          except:
              return False
  </code></pre>
  
  <p>And here is the test code:</p>
  
  <pre><code>def test_initialize(self):
      service = OnlineService()
      service.can_connect_to_api = MagicMock(return_value=True)
  
      service.initialize(u'some_url', False, 3.42)
  
      service.can_connect_to_api.assert_called_once_with(3.42)
      assert service.webservice_url is u'some_url'
      assert service.verify_ssl is False
      assert service.connected is True
  
  @patch('api.Resource')
  @patch('api.API')
  def test_can_connect_to_api(self, api_mock, resource_mock):
      api_instance = api_mock.return_value
      api_instance.Ping = resource_mock.return_value # is this step really necessary?
      api_instance.Ping.get.side_effect = [None, HTTPError()]
  
      service = OnlineService()
  
      connected = service.can_connect_to_api(5.0)
      assert connected is True
  
      connected = service.can_connect_to_api(5.0)
      assert connected is False
  </code></pre>
  
  <p>Currently the test passes if I run it. Commenting out the line we're discussing gives me the following failure in <code>test_can_connect_to_api</code>:</p>
  
  <pre><code>======================================================================
  FAIL: Services.tests.test_OnlineService.TestOnlineService.test_can_connect_to_api
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "C:\Development\Projects\app\venv\lib\site-packages\nose\case.py", line 197, in runTest
      self.test(*self.arg)
    File "C:\Development\Projects\app\venv\lib\site-packages\mock.py", line 1201, in patched
      return func(*args, **keywargs)
    File "C:\Development\Projects\app\src\Services\tests\test_OnlineService.py", line 47, in test_can_connect_to_api
      assert connected is False
  AssertionError
  
  ----------------------------------------------------------------------
  Ran 1 test in 0.013s
  
  FAILED (failures=1)
  </code></pre>