Skip to content

[PhpUnitBridge] support ClockMock and DnsMock with PHPUnit 10+ #58467

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

Merged
merged 1 commit into from
Oct 23, 2024

Conversation

xabbuh
Copy link
Member

@xabbuh xabbuh commented Oct 5, 2024

Q A
Branch? 7.2
Bug fix? no
New feature? yes
Deprecations? no
Issues Fix #49069
License MIT

@carsonbot carsonbot added this to the 7.2 milestone Oct 5, 2024
@carsonbot carsonbot changed the title [PhpUnitBridge] support ClockMock and DnsMock with PHPUnit 10+ [PhpUnitBridge] support ClockMock and DnsMock with PHPUnit 10+ Oct 5, 2024
@xabbuh xabbuh force-pushed the issue-49069 branch 2 times, most recently from 803602a to 16b6f37 Compare October 5, 2024 21:43
@xabbuh xabbuh added the ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" label Oct 7, 2024
Copy link
Member

@alexandre-daubois alexandre-daubois left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Copy link
Member

@stof stof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This misses the equivalent of the $mockedNamespaces constructor argument of the SymfonyTestsListener.
This constructor argument is important because the "hack" used to mock clock and dns functions requires being applied before the first use of those functions in a given namespace (because PHP caches the fact that a function should fallback to the global namespace). So registering the mock only when starting that test can be too late if some other (previous) tests execute code in the same namespace that use those functions.

And the SymfonyTestsListenerTrait also registers mocks early when starting the testsuite rather than the test, for the same reason.

@xabbuh
Copy link
Member Author

xabbuh commented Oct 8, 2024

This misses the equivalent of the $mockedNamespaces constructor argument of the SymfonyTestsListener.
This constructor argument is important because the "hack" used to mock clock and dns functions requires being applied before the first use of those functions in a given namespace (because PHP caches the fact that a function should fallback to the global namespace). So registering the mock only when starting that test can be too late if some other (previous) tests execute code in the same namespace that use those functions.

If I didn't miss anything PHPUnit doesn't allow to pass array parameters to an extension which makes this harder to implement. One possible way to implement this feature that I see is supporting JSON encoded environment variables. What do you think?

@OskarStark OskarStark changed the title [PhpUnitBridge] support ClockMock and DnsMock with PHPUnit 10+ [PhpUnitBridge] support ClockMock and DnsMock with PHPUnit 10+ Oct 8, 2024
@stof
Copy link
Member

stof commented Oct 8, 2024

Maybe we can use a comma-separated list of namespaces for the values of parameters (simpler to write than using JSON inside an XML node)

@xabbuh xabbuh force-pushed the issue-49069 branch 4 times, most recently from 3dd81e9 to 08b7ecc Compare October 8, 2024 11:06
@xabbuh
Copy link
Member Author

xabbuh commented Oct 8, 2024

I have updated the PR to register the namespaced functions as soon as possible, merged the two extensions and made it possible to register comma-separated, custom namespaces when registering the extension


foreach ($test->metadata() as $metadata) {
if ($metadata instanceof Group && 'time-sensitive' === $metadata->groupName()) {
ClockMock::withClockMock(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SymfonyTestsListenerTrait also registers the mock on starting the test in addition to enabling it. Is is safe to drop that part ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this already happens in the RegisterClockMockSubscriber which is run on the test suite level, doing it here as well would just redo what already happened before

@stof
Copy link
Member

stof commented Oct 8, 2024

I just re-discovered that the phpunit-bridge also has a CoverageListener (separate from the SymfonyTestsListener). Should we port it to a separate CoverageExtension ? and is it even possible to port it ?

@xabbuh
Copy link
Member Author

xabbuh commented Oct 8, 2024

Looking at the code I guess that it should be possible to port it. Do we have an example test on which we could try such a migrated extension?

@xabbuh
Copy link
Member Author

xabbuh commented Oct 8, 2024

Ah I see we have tests for it. I will see if I can find some time to work on it. Will send a different PR then.

Copy link
Member

@stof stof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have a way to have CI jobs (or steps in our existing jobs) running tests of the phpunit-bridge against different versions of PHPUnit (with the appropriate skipping of incompatible tests) ?

This PR does not seem to have any test.


class SymfonyExtension implements Extension
{
public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also needs to enable the DebugClassLoader if available, as done in SymfonyTestsListenerTrait.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not enable the DebugClassLoader here on purpose. PHPUnit defers the execution of bootstrapping extensions until the test suite to run was actually loaded. Thus, enabling the class loader here is too late to trigger deprecations for classes that have been loaded before. Right now, the only place to enable it early enough is a custom bootstrap file (like done in #58370).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But for projects that don't use a custom bootstrap file, I don't see which custom code can run before the loading of the testsuite. So the autoloading of custom classes will still probably happen after that point.
So the bootstrapping of extensions looks like a good place to register it for a better DX for the simple case (DebugClassLoader::enable is already handling the case where autoloaders have already been wrapped by a DebugClassLoader, so it is fine if both the bootstrap file and the extension bootstrapper call it)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough, this would still fail if a class (e.g. a fixture) is defined in the same file as a test, but it will probably still cover 99% of the other use cases

@xabbuh xabbuh force-pushed the issue-49069 branch 6 times, most recently from 90ff906 to c9d3d5e Compare October 15, 2024 10:45
@xabbuh
Copy link
Member Author

xabbuh commented Oct 15, 2024

@stof I added tests to ensure that the mocked functions from both the ClockMock and the DnsMock are registered with the extension. I'm gonna check to also add a test covering the triggering of a deprecation by the DebugClassLoader.

@xabbuh xabbuh force-pushed the issue-49069 branch 2 times, most recently from e217507 to f750beb Compare October 15, 2024 11:39
@xabbuh xabbuh force-pushed the issue-49069 branch 3 times, most recently from ee2e5aa to 869c6d4 Compare October 15, 2024 12:47
@xabbuh xabbuh requested a review from nicolas-grekas October 15, 2024 13:18
@xabbuh xabbuh requested a review from derrabus October 15, 2024 13:18
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to trust you on this one :)
Let's merge and iterate! (and unlock your other PRs 💪 )

@xabbuh xabbuh merged commit 8cb4a2f into symfony:7.2 Oct 23, 2024
9 of 11 checks passed
@xabbuh xabbuh deleted the issue-49069 branch October 23, 2024 20:10
@fabpot fabpot mentioned this pull request Oct 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature PhpUnitBridge ❄️ Feature Freeze Important Pull Requests to finish before the next Symfony "feature freeze" Status: Reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[PHPUnit bridge] Support for PHPUnit 11.1+
6 participants