title: Symfony 2 functional tests with mocked services
body: <p>I have a controller I'd like to create functional tests for.  This controller makes HTTP requests to an external API via a <code>MyApiClient</code> class.  I need to mock out this <code>MyApiClient</code> class, so I can test how my controller responds for given responses (e.g. what will it do if the <code>MyApiClient</code> class returns a 500 response).</p>
  
  <p>I have no problems creating a mocked version of the <code>MyApiClient</code> class via the standard PHPUnit mockbuilder: The problem I'm having is getting my controller to use this object for more than one request.</p>
  
  <p>I'm currently doing the following in my test:</p>
  
  <pre><code>class ApplicationControllerTest extends WebTestCase
  {
  
      public function testSomething()
      {
          $client = static::createClient();
  
          $apiClient = $this-&gt;getMockMyApiClient();
  
          $client-&gt;getContainer()-&gt;set('myapiclient', $apiClient);
  
          $client-&gt;request('GET', '/my/url/here');
  
          // Some assertions: Mocked API client returns 500 as expected.
  
          $client-&gt;request('GET', '/my/url/here');
  
          // Some assertions: Mocked API client is not used: Actual MyApiClient instance is being used instead.
      }
  
      protected function getMockMyApiClient()
      {
          $client = $this-&gt;getMockBuilder('Namespace\Of\MyApiClient')
              -&gt;setMethods(array('doSomething'))
              -&gt;getMock();
  
          $client-&gt;expects($this-&gt;any())
              -&gt;method('doSomething')
              -&gt;will($this-&gt;returnValue(500));
  
          return $apiClient;
      }
  }
  </code></pre>
  
  <p>It seems as though the container is being rebuilt when the second request is made, causing the <code>MyApiClient</code> to be instantiated again.  The <code>MyApiClient</code> class is configured to be a service via an annotation (using the JMS DI Extra Bundle) and injected into a property of the controller via an annotation.</p>
  
  <p>I'd split each request out into its own test to work around doing this if I could, but unfortunately I can't: I need to make a request to the controller via a GET action and then POST the form it brings back.  I'd like to do this for two reasons: </p>
  
  <p>1) The form uses CSRF protection, so if I just POST directly to the form without using the crawler to submit it, the form fails the CSRF check.</p>
  
  <p>2) Testing that the form generates the correct POST request when it is submitted is a bonus.</p>
  
  <p>Does anyone have any suggestions on how to do this?</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>This can be expressed in the following unit test that does not depend on any of my code, so may be clearer:</p>
  
  <pre><code>public function testAMockServiceCanBeAccessedByMultipleRequests()
  {
      $client = static::createClient();
  
      // Set the container to contain an instance of stdClass at key 'testing123'.
      $keyName = 'testing123';
      $client-&gt;getContainer()-&gt;set($keyName, new \stdClass());
  
      // Check our object is still set on the container.
      $this-&gt;assertEquals('stdClass', get_class($client-&gt;getContainer()-&gt;get($keyName))); // Passes.
  
      $client-&gt;request('GET', '/any/url/');
  
      $this-&gt;assertEquals('stdClass', get_class($client-&gt;getContainer()-&gt;get($keyName))); // Passes.
  
      $client-&gt;request('GET', '/any/url/');
  
      $this-&gt;assertEquals('stdClass', get_class($client-&gt;getContainer()-&gt;get($keyName))); // Fails.
  }
  </code></pre>
  
  <p>This test fails, even if I call <code>$client-&gt;getContainer()-&gt;set($keyName, new \stdClass());</code> immediately before the second call to <code>request()</code></p>