feature #35893 [HttpClient][DI] Add an option to use the MockClient in functional tests (GaryPEGEOT)

This PR was squashed before being merged into the 5.2-dev branch.

Discussion
----------

[HttpClient][DI] Add an option to use the MockClient in functional tests

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       |
| License       | MIT
| Doc PR        | TODO

Let's say you want to mock HTTP responses in your test or dev environment:

First, you create an invokable class responsible of generating the response:
```php
namespace App\Tests;

use Symfony\Contracts\HttpClient\ResponseInterface;

class MyAwesomeCallback
{
    public function __invoke(string $method, string $url, array $options = []): ResponseInterface
    {
        // load a fixture file or generate dynamic data
    }
}
```

Then configure it:
```yaml

# config/services_test.yaml
services:
   # ...
   App\Tests\MyAwesomeCallback: ~

# config/packages/test/framework.yaml
framework:
    http_client:
        mock_response_factory: App\Tests\MyAwesomeCallback
```

The HttpClient will now be using MockHttpClient in your functional test:
```php
$client = static::createClient();

// No live HTTP connection made
$client->request('GET', '/path-with-http-call');
```

Commits
-------

b53739c79d [HttpClient][DI] Add an option to use the MockClient in functional tests
This commit is contained in:
Fabien Potencier 2020-08-27 16:44:19 +02:00
commit fe4d92806b
7 changed files with 52 additions and 0 deletions

View File

@ -1450,6 +1450,9 @@ class Configuration implements ConfigurationInterface
->end()
->end()
->end()
->scalarNode('mock_response_factory')
->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable.')
->end()
->arrayNode('scoped_clients')
->useAttributeAsKey('name')
->normalizeKeys(false)

View File

@ -63,6 +63,7 @@ use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator;
use Symfony\Component\Form\FormTypeExtensionInterface;
use Symfony\Component\Form\FormTypeGuesserInterface;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\ScopingHttpClient;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
@ -2010,6 +2011,12 @@ class FrameworkExtension extends Extension
$container->registerAliasForArgument('psr18.'.$name, ClientInterface::class, $name);
}
}
if ($responseFactoryId = $config['mock_response_factory'] ?? null) {
$container->getDefinition($httpClientId)
->setClass(MockHttpClient::class)
->setArguments([new Reference($responseFactoryId)]);
}
}
private function registerMailerConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader)

View File

@ -510,6 +510,7 @@
</xsd:sequence>
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:attribute name="max-host-connections" type="xsd:integer" />
<xsd:attribute name="mock-response-factory" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="http_client_default_options" mixed="true">

View File

@ -0,0 +1,8 @@
<?php
$container->loadFromExtension('framework', [
'http_client' => [
'default_options' => null,
'mock_response_factory' => 'my_response_factory',
],
]);

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config>
<framework:http-client mock-response-factory="my_response_factory">
<framework:default-options />
</framework:http-client>
</framework:config>
</container>

View File

@ -0,0 +1,4 @@
framework:
http_client:
default_options: ~
mock_response_factory: my_response_factory

View File

@ -41,6 +41,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBa
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Serializer\FormErrorNormalizer;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\ScopingHttpClient;
use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass;
use Symfony\Component\Messenger\Transport\TransportFactory;
@ -1567,6 +1568,21 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertEquals(new Reference('app.another_bus'), $container->getDefinition('mailer.mailer')->getArgument(1));
}
public function testHttpClientMockResponseFactory()
{
$container = $this->createContainerFromFile('http_client_mock_response_factory');
$definition = $container->getDefinition('http_client');
$this->assertSame(MockHttpClient::class, $definition->getClass());
$this->assertCount(1, $definition->getArguments());
$argument = $definition->getArgument(0);
$this->assertInstanceOf(Reference::class, $argument);
$this->assertSame('my_response_factory', (string) $argument);
}
protected function createContainer(array $data = [])
{
return new ContainerBuilder(new EnvPlaceholderParameterBag(array_merge([