Open gregurco opened 6 years ago
@gregurco : Here is how I did it: https://gist.github.com/Neirda24/d662dda169518dc75a5beb924c4182c2 tell me what you think
Any updates on this topic. This is definitely a prerquisite for this bundle to be considered usable in a production system.
I plan to write it as soon as will finish with guide for plugins. It takes some time.
Any thoughts about how to properly provide mock clients in functional tests?
I've been able to configure the bundle to use the MockHandler as described, but don't know how to properly provide the mocked responses in my tests -- the MockHandler queue is always empty.
Any news about it?
As we use this as our one of the main bundle need some documentation (examples is great too) about how to mock it the right way.
@bropp @ggagosh there are a lot of methods how to mock client. Each method is better in special cases. Could you please provide more details on your requirements from your projects and I will try to provide more information. Probably based on these answers we will be able to create documentation page.
Hi, first of all, thank you for your lib. I'd like to know if there is a example of how to do the mock. I replaced the handler, it's the MockHandler, but I can't add any request to the queue in the tests. I tried the setHandler
method from Guzzle Client and I tried to use reflection class to get the Mock class and append things, but without success.
Could somebody help me with this, please? Thnx in advance
Well, I think I found a way through. One thing that I didn't mention before it was that I'm using api-platform and because I'm using api-platform, I'm using its ApiTestCase to write the functional tests, and the problem was that my modifications weren't being applied in the container. But, if I disable the kernel reboot (static::createClient()->disableReboot()
), it keeps the modification through all the request at that particular test.
So, I used the code from the tests that @rrajkomar wrote for #221 and disabling the reboot:
static::createClient()->disableReboot();
$cli = static::createClient()->getContainer()->get('eight_points_guzzle.client.<client_name>');
$handlerStack = $cli->getConfig('handler');
$handlerStackRefl = new \ReflectionClass($handlerStack);
$handler = $handlerStackRefl->getProperty('handler');
$handler->setAccessible(true);
$mock = $handler->getValue($handlerStack);
After that, you can append
any request into the MockHandler, like:
$mock->append(new Response(200, [], ''));
Api plataform uses SF4, so I just set the MockHandler in the services_test.yaml
:
# config/services_test.yaml
eight_points_guzzle:
clients:
<client_name>:
handler: 'GuzzleHttp\Handler\MockHandler'
All that set, you're good to go. I hope it helps ^^
Coming back to this topic after a while, and a lot more use case experience, I'm no longer convinced the MockHandler was been the best way to implement the mocking mechanism. Now using a lot of Behat tests, I'm faced with an issue that could not be solved by any of the proposed solution (I even tried an adapted version of @matheusfaustino 's solution, sadly it didn't work as expected)
When using Behat testing, the MockHandler that you fill up with MockResponses is not taken into account once the actual code is called. This is where disabling the client reboot might have solved some use cases when using the symfony driver (or so I hoped) but even then, when switching to any other driver the solution would no longer be working.
All this leads me to believe going towards a middleware based mocking mechanism might be the best way to handle this problem (although I'm definitely not a fan of a record / replay system, this is so far the most usable I found)
Also it might be the opportunity to revisit the discussion we had way back about setting up a base interface for middlewares (#232): With autowiring now being a best practice, we could use the interface to get an easily extendable system for middlewares. (The same kind of system could also be used for plugins, currently having to go change the Kernel class is rather cumbersome)
@gregurco WDYT ?
I am just a couple of years late, I solved these problems building a Guzzle client that uses a router to dispatch mocked routes/responses.
https://packagist.org/packages/doppiogancio/mocked-client
@rrajkomar let me know if my package can help you.
The solution of @matheusfaustino worked flawless, thnx. As of today, the getConfig()
option is deprecated and will be removed in Guzzle 8.0 (https://github.com/guzzle/guzzle/issues/2514). In case your static analyser complains about deprecated function usage this should be the alternative:
$handler = self::getContainer()->get('eight_points_guzzle.handler.{client_name}');
$handler->append(new Response(...));
Btw 1: Removed reflection usage because a service definition is exposed when a handler is set inside the config.
Btw 2: I've also removed the disableReboot()
statement, as it's unnecessary when the test only contains a single request. The kernel only reboots during multiple requests. Remember to call disableReboot()
if you use self::$client->request()
multiple times.
Write a guide how to mock clients in functional tests.