0

question summary

Is it possible to inject stubs/mocks to the symfony di container in my test cases to simulate different external api responses?

  • test that my application sends an email if the api returns an error (i want to inject a stub for my http client class that returns a HTTP 500)
  • test that my application returns the correct result using 2 different APIs as source (i want to inject both HTTP Clients as stub with a specific result body)

details

i want to write functional tests for an silex application that uses the symfony di container. The application uses multiple API's as backend to fullfill the client reuquests.

The code injects an abstracted http client to the api client where i'm able to inject a http api client stub.

class AwesomeApiClient
   __construct(MyHttpClient $httpClient);

class MyApiHttpClient

This does work pretty good with unit testing.

Now i want to write functional tests. I extended the silex WebTestCase and implemented the application initialization. The MyApiHttpClient is injected with the symfony di container.

Now i want to do something like this:

# symfony di container does not allow this
$this->getDiContainer()->set('my_http_client', $myHttpClientStubInstance);

i want to configure my stub in every test so i'm able to test different (e.g. error, success) responses for the same request.

things i've tried:

using setter injection at runtime

$his->getDiContainer()->get('MyApiClient')->setHttpClient($myMock);

The DiContainer returns a new instance for everytime i call the get method. That does make absolutely sense. So this does not work.

overriding the http client in the di container

$this->getDiContainer->set('MyHttpClient', $myHttpClientStub);

Does not work because symfony does not allow to change definitions at runtime. Also it seems to take a definition, not an instance.

PHP-VCR

Does work with a few changes in my production code because it messes up the HTTP Headers in my curl header callbacks. Does not work for other services (rabbitmq...)

RomanKonz
  • 1,027
  • 1
  • 8
  • 15

1 Answers1

1

According to this, it should be possible to set mock in the DI container.

$client = self::createClient();

$serviceA = $this->getMockBuilder('ServiceA')
    ->disableOriginalConstructor()
    ->getMock();

$client->getContainer()->set('my_bundle.service.a', $serviceA);
lchachurski
  • 1,770
  • 16
  • 21