Problem/Motivation
PHPUnit 13 was released in Feb 2026.
Proposed resolution
Remaining tasks
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Issue fork drupal-3574681
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mondrakeComment #3
mondrakeComment #5
catchFor #3527936: Introduce support for PHPUnit 12 we fixed all the deprecations in advance of the update, which was a lot of work.
For PHPUnit 13, without knowing the scale of the work we need to do, I'm wondering if we should take the inverse approach - skip as many deprecations as we can, so we can update the constraint - the idea being that if we do this, it will be possible for contrib to test against phpunit 13 earlier. Then we can work on removing the skips. Depends on whether this is even a viable approach though.
Comment #6
dcam commentedI predict that the big issue we'll face going to PHPUnit 13 is the deprecation of
with()for mock objects that do not set an expectation. I tried to correct as many of them as I could during the PHPUnit 12 prep, but that was entirely a manual effort. They did not raise any notices in PHPUnit 12. So it was on me to locate and fix them. What's worse is that I undoubtedly created a some, especially in the early days of the project before the deprecation happened. I caught a lot on re-reviews of uncommitted work, but without checking I feel certain some went in.Comment #7
mondrakeBefore we jump into this, I wanted to share a few considerations. I am not jumping to conclusions or recommendations, but I think we need to discuss this a bit.
1) There is no way to selectively skip deprecations/notices generated by PHPUnit. These use PHPUnit's internal event system, not the
trigger_error(..., E_USER_DEPRECATED)mechanism for which we can intercept the errors in our own error handler before PHPUnit. PHPUnit deprecations/notices can be configured not to fail the tests (via the command line or the configuration file), but it's all-in or all-out.2) PHPUnit makes changes to its internals and adds deprecations within its latest major. On one side, this leads to minors that require additional patch releases to stabilize (PHPUnit has no alpha/beta releases). On the other side, this leads to deprecations that have quite an impact on large project like Drupal, that require time and work broken down in multiple tickets to address the changes (see the recent mock-to-stub work, deprecations appeared on the last minor of PHPUnit 12, it took months to fix... and before that move, the bump to PHPUnit was practically ready to go). In other words, targeting the cutting edge may mean sudden deprecations to be dealt with on a large scale, and higher risk to hit PHPUnit's own bugs.
Comment #8
mondrakeNR to trigger a discussion on #7.
Comment #9
catchDiscussed this with @mondrake and @Taran2L in slack a bit.
Short version is:
phpunit will continue to add new deprecations to the 13.x branch until December this year, also early 13.x patch releases often have bugs in.
So we should consider specifically staying on PHPUnit 12, and then update to PHPUnit 13's last minor release at the end of the year.
At this point PHPUnit 14 will be releasing, but given PHPUnit has a one major year cycle and Drupal has a two year major cycle, we can always try to update to the 'last minor of the most recent major'.
Occasionally we might get stuck (e.g. Drupal 11 is stuck on PHPUnit 12 due to dropping support for test annotations), but we can't predict that in advance.
If we follow that, then the result here would be postponing this issue until November/December and releasing Drupal 12.0 on PHPUnit 12.
I have one extra question here - whether we should lock to PHPUnit 12 but allow PHPUnit 13 so that we can e.g. run the updated dependencies job to catch new deprecations, but that could also end up being more work compared to doing it when it's all settled.
Comment #10
mondrakein order to allow 13, and not fail in case of deprecations/notices, we would have to remove the configuration entries that lead to test failure in that case. or have a version-dependent configuration file
Comment #11
catchOK that sounds sufficiently fiddly that we could just wait for the last minor and concentrate the work.
Comment #12
mondrakeI think the summary is:
how does it sound?
Comment #13
mondrakeBTW, this does not mean that in the meantime we can not have separate issues to work on deprecations already identified - for example, the MR here spots the
Using with*() without expects() is deprecatedinstances that I think can be already fixed under PHPUnit 12Comment #14
catch#13 is also a good point and means we can still spread the work out over time without actually changing the constraint in HEAD.
Comment #15
dcam commentedIn terms of easing the transition: we need to commit more things for upcoming versions sooner. I wish I had done this much earlier in the mock/stub fixing process. For some reason I didn't think of it until I was nearly done and then there was little point. But you all saw we had that phpunit12.patch file that had to be applied if you wanted to run the tests locally. It contained the basic changes that were necessary for getting version 12 to work,
__construct()override removals and the v12TestCompatibilityTrait.I realize that the constructor deletions were a one-time thing. And someone, probably @mondrake, said it's time to get rid of the traits. My point is that there may be things like that with every new version. Doing these things shouldn't wait until it's time to upgrade the dependency if at all possible. They are a barrier to getting the work done in the first place. They're effectively issue blockers unless you know what you're doing. They should be given Major priority at a minimum and be worked on and committed with haste.
Comment #16
dcam commented#12 This sounds reasonable to me.
Comment #17
andypostmaybe it could have a weekly PHPUnit 13 pipeline?
Comment #18
mondrake#17 maybe we could put a scheduled pipeline behind the MR here. That would start failing anytime a dependency is updated, though.
Comment #19
mondrakeBTW @andypost any plan to have a PHP 8.6 image for testing? likewise the PHP 8.5 one that was opened more or less this time one year ago?
Comment #20
andypostGood idea will cook one tonight!
Comment #21
andypost@mondrake pushed initial image and scheduled reduild
00 12 * * 5 Etc/UTC- there's already internal changes so extensions are patched, also first alpha planned to July 2 https://wiki.php.net/todo/php86ref https://git.drupalcode.org/project/drupalci_environments/-/jobs/9176064
Comment #22
mondrakeThanks @andypost! I filed #3582508: [CI] Run Unit tests on PHP 8.6.
Comment #23
smustgrave commentedThink everyone has been a +1 to this idea. I joked that we just got 12 in and already going for 13?!?
Only moving to NW as there are some test failures.
Comment #24
mondrake“Postponed” seems more accurate to me.
Comment #25
catchAdding the date in the issue title.
Comment #26
mondrake… and the PHPUnit minor version to target.
Comment #27
mondrakePHPUnit 13.2 was released today.
expectExceptionMessagewas replaced by eitherexpectExceptionMessageIsorexpectExceptionMessageIsOrContainsDeprecationHandlerComment #28
mondrakeLooks like 13.2 disattends the fact that we set an error handler in bootstrap.php.
What we are doing is we set the
\Drupal\TestTools\ErrorHandler\BootstrapErrorHandlerwhich itself falls back to PHPUnit's own one. So we can exclude the ignored deprecations (those ignored via the ignore file) and return to test execution without even letting PHPUnit know that a deprecation was triggered.13.2 reverses that - it always sets its own error handler as the main one, and only falls back to
\Drupal\TestTools\ErrorHandler\BootstrapErrorHandlerafter the error (including deprecation ones) have been already collected. So the entire 'deprecation ignore' process is browen.Comment #29
mondrakePlease review #3589108: Refactor DeprecationHandler into a standard PHPUnit extension - that one will be blocking this one as we need to get rid of large portions of
DeprecationHandleras of PHPUnit 13.3.