-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpClient] Configure MockClient
if mock_response_factory has been set on a scoped client
#52265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 7.4
Are you sure you want to change the base?
Conversation
09ce17e
to
5091cc6
Compare
@nicolas-grekas I'll fix the last tests if you like the direction of the PR :) |
|
||
|
||
$container->register('http_client.mock_client.' . $name, MockHttpClient::class) | ||
->setDecoratedService($httpClientTransport, null, -10) // lower priority than TraceableHttpClient (5) | ||
->setArguments( | ||
$responseFactoryId === true ? [] : [new Reference($responseFactoryId)]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks good to me but I don't get the true
case, what is it for? we don't have it for the general mock factory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is if I want to have a mock client here but I do not want to configure the responsefactory as a service but just do it in the test. I considered having a separate attribute for it, i.e. mock: true
and then having the mock_response_factory be an optional attribute if needed.
Maybe being able to just say "mock this" and then add responses in the client is the main use case - i.e. that mock should be a separate parameter to make it more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Let's do the same for the global factory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. So add a mock: bool to both the global factory and the specific factory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolas-grekas : ping :) I just wanted to get a reaction to the last question before working on the PR. Also: Is it possible to get this into the 6.x series?
MockClient
if mock_response_factory has been set on a scoped client
a045ef5
to
182182c
Compare
182182c
to
0e53491
Compare
…d client. This makes it possible to use different mock response factories on different services and also to easily test services that uses http client endpoints. It also generates an extra test service http_client.mock_client.$name that can be used to configure the MockHttpClient instance if you want to inject a different responsefactory. We also change the framework.http_client.mock_client_factory attribute to allow for a boolean so you can just mock without injecting a responsefactory in the service setup.
0e53491
to
5fd1b32
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not core team so those remarks are my own. Only here to help ;)
|
||
if ($responseFactoryId = $scopeConfig['mock_response_factory'] ?? null) { | ||
$container->register('http_client.mock_client.'.$name, MockHttpClient::class) | ||
->setDecoratedService($httpClientTransport, null, -10) // lower priority than TraceableHttpClient (5) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is also decorated with priority 10
for the global mock_response_factory
. Maybe worth having a lower priority here so it superseeds the global one ?
if (null === $scope) { | ||
$baseUri = $scopeConfig['base_uri']; | ||
unset($scopeConfig['base_uri']); | ||
|
||
$container->register($name, ScopingHttpClient::class) | ||
->setFactory([ScopingHttpClient::class, 'forBaseUri']) | ||
->setArguments([new Reference('http_client.transport'), $baseUri, $scopeConfig]) | ||
->setArguments([$httpClientTransport, $baseUri, $scopeConfig]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure this change is needed. Sure you save a few objects and memory but only during build time and this is like 3 objects.
@@ -2521,7 +2530,7 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder | |||
if ($responseFactoryId = $config['mock_response_factory'] ?? null) { | |||
$container->register('http_client.mock_client', MockHttpClient::class) | |||
->setDecoratedService('http_client.transport', null, -10) // lower priority than TraceableHttpClient (5) | |||
->setArguments([new Reference($responseFactoryId)]); | |||
->setArguments(true === $responseFactoryId ? [] : [new Reference($responseFactoryId)]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the goal here ? Tell me if I'm wrong but it looks like you are trying to set it to []
only if at least one dedicated mock was set. But then what if you have a global one and one specific for only one of the clients ?
Because that variable is set only during foreach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Because that variable " <-- do you mean $responseFactoryId which is set in the if ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup It is created and overidden in foreach at each iteration. So the only value it could have would be the last scoped client says its true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into this :)
.../Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php
Outdated
Show resolved
Hide resolved
@@ -6,4 +6,4 @@ framework: | |||
log: true | |||
http_client: | |||
default_options: ~ | |||
mock_response_factory: my_response_factory | |||
mock_response_factory: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand properly the true
. Do you have a pending documentation PR that could help me understand ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From a comment above:
It is if I want to have a mock client here but I do not want to configure the responsefactory as a service but just do it in the test. I considered having a separate attribute for it, i.e. mock: true and then having the mock_response_factory be an optional attribute if needed.
Maybe being able to just say "mock this" and then add responses in the client is the main use case - i.e. that mock should be a separate parameter to make it more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I think a dedicated parameter is better because I do not find intuitive to set this to true to delegate at runtime during test to be able to provide the factory in question. Maybe some other approach would be a better fit ? Don't have an idea at the moment though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Neirda24 maybe the problem is the parameter name in general?
If we renamed the parameter name to mock_responses
then it could work the same way going forward. The problem then is backward compatibility which is harder to solve.
IMHO The right way would be be to change the parameter name, BUT due to backwards compability (as I understand Symfony's policy) this would require some extra gluecode to keep both options. One of the reasons I'm inclined to keep this current PRs solution is that it requires less code and tests than two options.
I'm more than willing to do a documentation PR for it though :)
Also: If you mock the default client then this choice becomes the default for scoped clients
Ok, i've now updated this PR to separate out mock_client from mock_response_factory and also add tests and handling of overriding the options in scoped clients. Example config:
Note: Today mock_response_factory is directly under the http_client key. Maybe it both should be moved under the |
@Neirda24 do the changes satisfy your concerns? :) |
This makes it possible to use different mock response factories on different services and also to easily test services that uses http client endpoints.
It also generates an extra test service http_client.mock_client.$name that can be used to configure the MockHttpClient instance if you want to inject a different responsefactory.
Example usage:
The first client will use the acme_mock_factory for mock_factory while
otherClient
will be a MockHttpClient but without a set responsefactory (it can be configured in the test).