-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[PhpUnitBridge] Supress deprecation notices thrown when getting private services from container in tests #27312
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
Conversation
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.
Lgtm thanks! Here are a few minor comments. The most important one is that we should do the same with the "has" method.
// fetching of private services within tests, so we no longer | ||
// need to warn about this behavior: | ||
// | ||
// https://symfony.com/blog/new-in-symfony-4-1-simpler-service-testing |
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.
Should be removed, we usually don't link to the blog.
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.
Easy enough
// triggered deprecation notice; and the fourth event (index 3) | ||
// represents the action that called the deprecated code. In the | ||
// scenario that we want to suppress, the 4th event be an object | ||
// instance of PHPUnit_Framework_TestCase. |
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.
Should use backslash instead of underscore
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.
easy enough
// represents the action that called the deprecated code. In the | ||
// scenario that we want to suppress, the 4th event be an object | ||
// instance of PHPUnit_Framework_TestCase. | ||
if (isset($trace[3]) && isset($trace[3]['object'])) { |
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.
The first isset is not needed
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 didn't originally have it, because I've never ever sen a stack track (particularly one for a framework) less than 4 elements, but I added it "just to be safe". I will remove it.
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.
You don't need it because isset
both check that $trace[3]
exists and then that $trace[3]['object']
exists: https://3v4l.org/4XGmL
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.
ahh, thanks for the tip, should have known
// instance of PHPUnit_Framework_TestCase. | ||
if (isset($trace[3]) && isset($trace[3]['object'])) { | ||
$noticeSource = $trace[2]; | ||
$noticeSourceCaller = $trace[3]['object']; |
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'd suggest to remove these two intermediary variables: the note just above is clear enough
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.
easy enough
if (isset($trace[3]) && isset($trace[3]['object'])) { | ||
$noticeSource = $trace[2]; | ||
$noticeSourceCaller = $trace[3]['object']; | ||
$isPrivateServiceNotice = (false !== strpos($msg, ' service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead.')); |
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 missing the message triggered by the "has" method, which should be handled here also. Maybe just check for the first common words? Should be enough since we also check the class + method triggering this just below.
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 point, I can check for the common prefix of " service is private,
instead. I will then also need to change $isNoticeForContainerGetUsage
to $isNoticeForContainerGetHasUsage
and also include coverage for the function equaling has
$noticeSource = $trace[2]; | ||
$noticeSourceCaller = $trace[3]['object']; | ||
$isPrivateServiceNotice = (false !== strpos($msg, ' service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead.')); | ||
$isNoticeForContainerGetUsage = ('Symfony\Component\DependencyInjection\Container' === $noticeSource['class'] && 'get' === $noticeSource['function']); |
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.
Enclosing brackets should be removed (same above)
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.
no problem
@nicolas-grekas, I think the most recent commit above address all of your notes, but I'm happy to do another pass if need be. Thanks for the feedback. |
…container in tests
Thank you @arderyp. |
…rvies from container in tests (arderyp) This PR was submitted for the master branch but it was squashed and merged into the 4.1 branch instead (closes #27312). Discussion ---------- Supress deprecation notices thrown when getting private servies from container in tests | Q | A | ------------- | --- | Branch? | 4.1 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #27037 | License | MIT | Doc PR | na This is my first attempt at fixing #27037. This approach works for me, and I believe it will work globally, but I am not entirely sure if it is the "right" way to do this. Its not that I think it's the "wrong" way to do it, its just that the `phpunit-bridge` code structure is not the type of code structure that I'm used to, and I'm still new to this project, so I don't know all of the ins and outs, or if there might be a more ideal place to inject the logic we want. Also, I think my code may be a bit redundant, and I was hoping to get feedback on that. @nicolas-grekas (or anyone else), do you think it is safe to simply check if the deprecation message contains the substring ` service is private, getting it from the container...`? if so, then I think we can simply get rid of my `$isNoticeForContainerGetUsage` bit altogether. If I am understanding things properly, `$isNoticeForContainerGetUsage` will always be true if `$isPrivateServiceNotice` is true, thus we can safely remove the former (as the later is more intuitive, IMO). The last thing I wanted to confirm was my interpretation of the stack trace, as detailed in my code comment. If the bit after `NOTE` is not correct, this code might not be a proper solution. I tested various contexts where the error should be suppressed (from within tests) and also where it should not (from within controllers, etc), which is what I based my `NOTE` comment on. Commits ------- 00603bf Supress deprecation notices thrown when getting private servies from container in tests
if (isset($trace[3]['object'])) { | ||
$isPrivateServiceNotice = false !== strpos($msg, ' service is private, '); | ||
$isNoticeForContainerGetHasUsage = 'Symfony\Component\DependencyInjection\Container' === $trace[2]['class'] && in_array($trace[2]['function'], array('get', 'has')); | ||
$noticeWasTriggeredByPhpUnitTest = $trace[3]['object'] instanceof \PHPUnit\Framework\TestCase; |
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.
shouldn't this test for the KernelTestCase instead (the parent TestCase does not have the client) ?
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.
Instanceof does it, isn't it? Not sure we need to be more strict, WDYT?
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.
@stof and @nicolas-grekas I didn't want to be any more strict than \PHPUnit\Framework\TestCase
because I for one have unit tests that extend this directly instead of KernelTestCase
. I'm not sure if I am accessing the service container on any of those, I'd have to check, but I doubt it. But, this might be a good point. Is the new TestContainer
explicitly tied to KernelTestCase
? If so, then the deprecation warning probably shouldn't be suppressed for raw extensions of \PHPUnit\Framework\TestCase
, as the TestContainer
only provides access to private services via extensions of KernelTestCase
, meaning attempts to do so via TestCase
extensions should throw errors/warnings.
If that is not the case, then I think making this comparison as general as possible by checking for extensions of TestCase
is fine.
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.
Can you check this question and make the PR if needed? The reasoning lgtm.
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 I will take a look when I get a chance tomorrow and report back
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.
see: #27342
Wouldn't this hide wrong usages of the container in tests on 3.4 which would then break when updating to 4.0? |
Based on the information provided in #27037, this PR should be reverted entirely, as it is hiding actual deprecated calls. the initial bug report was invalid. |
* 4.1: (26 commits) Revert "bug #27312 Supress deprecation notices thrown when getting private servies from container in tests (arderyp)" [HttpKernel] reset kernel start time on reboot Add code of Conduct links in our README bumped Symfony version to 4.0.12 [FrameworkBundle] Fix using test.service_container when Client is rebooted [DI] never inline lazy services updated VERSION for 4.0.11 updated CHANGELOG for 4.0.11 bumped Symfony version to 3.4.12 updated VERSION for 3.4.11 updated CHANGELOG for 3.4.11 Default testsuite to latest PHPUnit 6.* [Github] Update the pull-request template bumped Symfony version to 2.8.42 updated VERSION for 2.8.41 updated CHANGELOG for 2.8.41 Tweak Argon2 test config [HttpFoundation] Fix cookie test with xdebug [FrameworkBundle] cleanup generated test container [Serializer] Check the value of enable_max_depth if defined ...
This is my first attempt at fixing #27037.
This approach works for me, and I believe it will work globally, but I am not entirely sure if it is the "right" way to do this. Its not that I think it's the "wrong" way to do it, its just that the
phpunit-bridge
code structure is not the type of code structure that I'm used to, and I'm still new to this project, so I don't know all of the ins and outs, or if there might be a more ideal place to inject the logic we want.Also, I think my code may be a bit redundant, and I was hoping to get feedback on that. @nicolas-grekas (or anyone else), do you think it is safe to simply check if the deprecation message contains the substring
service is private, getting it from the container...
? if so, then I think we can simply get rid of my$isNoticeForContainerGetUsage
bit altogether. If I am understanding things properly,$isNoticeForContainerGetUsage
will always be true if$isPrivateServiceNotice
is true, thus we can safely remove the former (as the later is more intuitive, IMO).The last thing I wanted to confirm was my interpretation of the stack trace, as detailed in my code comment. If the bit after
NOTE
is not correct, this code might not be a proper solution. I tested various contexts where the error should be suppressed (from within tests) and also where it should not (from within controllers, etc), which is what I based myNOTE
comment on.