Problem/Motivation
While working on #3295821: Ignore: patch testing issue for PHP 8.2 attributes in testing issue I faced that some tests using to test properties that defined only on classes
So some mocks require to use different class/interface to prevent deprecation warnings
Steps to reproduce
See #3295821-91: Ignore: patch testing issue for PHP 8.2 attributes
visit https://www.drupal.org/node/3060/qa and choose one of latest runs on 10.0.x using php-8.2, for example https://www.drupal.org/pift-ci-job/2498879
Proposed resolution
Use classes instead of interfaces when creating mocks to make tests pass
The issue intended only for testing code, remaining changes are in #3309748-17: Define missing object properties on non-testing classes for PHP 8.2
Remaining tasks
- collect all changes from testing issue #3295821-91: Ignore: patch testing issue for PHP 8.2 attributes
- make sure tests pass on PHP 8.2
- review/commit
User interface changes
no
API changes
no
Data model changes
no
Release notes snippet
no
| Comment | File | Size | Author |
|---|---|---|---|
| #53 | interdiff.3309745.49-53.txt | 5.93 KB | longwave |
| #53 | 3309745-53.patch | 25.17 KB | longwave |
Comments
Comment #2
andypostImproved IS and linked #3309749: Modernize tests to pass on PHP 8.2
Comment #3
andypostSadly I failed to fix remaining mocks
Comment #4
andypostMoved all tests here
Comment #5
berdirFixed the entity unit tests. Needs cleanup, but there's just no way around creating subclasses with the properties, maybe phpunit will in the future add that annotation to mock classes, until then, this is what we need to do. That said, I'm not fond of these entity unit tests at all.
I'm almost certain that they are not adding any test coverage over the existing kernel and functional tests and contain a lot of complexity, i'd vote to just drop EntityUnitTest and EntityUrlTest at least, but that's for later.
Comment #6
berdirCoding style fixes.
Comment #8
andypostThank you! Another name needed)
Please reroll "ignore" issue with this changes or I can do it later
Comment #9
andypostFixed name collision
Comment #10
berdirthanks, not sure what our codiing standards are for such mock classes and whether or not we need to document them and their properties properly.
Comment #11
andypostSo we need to fix condition->sqlQuery first to remove noise from failed tests and add attributes
Comment #12
andypost@Berdir it looks RTBC except naming now different to the "Child"
Comment #13
andypostChanged all
EntityBaseTesttoEntityBaseChildfor consistency and grepabilityAlso added last mock fix for https://dispatcher.drupalci.org/job/drupal_patches/149881/testReport/jun...
Ref #3295821-113: Ignore: patch testing issue for PHP 8.2 attributes
Comment #14
andypostComment #15
andypostand interdiff 9 vs 14
Comment #17
andypostreverted rename
Comment #18
berdirUnsure about this one. The only difference is that PHP 8.2 now apparently starts the class with a \. I'm wondering if we should instead ensure a consistent output, but I'm not sure in which direction that should even go. Always with \ or never with \?
Alternatively, we could ltrim() the output of Variable::export() for now in the test.
Still not sure if we should document the helper classes, core is quite inconsistent in that regard. I feel like at least a class docblock that explains why we are doing it ("Mock class with required properties defined to avoid dynamic property deprecations") would be good?
Comment #19
andypostMaybe we add changes from #3309748-15: Define missing object properties on non-testing classes for PHP 8.2 except view handler there if it's all about tests?
Comment #20
berdirYeah, I'd say that makes sense. See comment #5.4 on the randomValue properties, we can change the test instead of adding those.
Comment #21
andypostWorking on split, there's only few failures left
https://www.drupal.org/pift-ci-job/2484518
Comment #22
andypostEvent test needs clean-up issue for Symfony 6.2 but the
$nameproperty still there and defined https://github.com/symfony/symfony/blob/6.2/src/Symfony/Component/EventD...so filed #3312075: Make \Drupal\Tests\Component\EventDispatcher\ContainerAwareEventDispatcherTest more inline with Symfony 6.2
Added changes from #3309748: Define missing object properties on non-testing classes for PHP 8.2 and fixed tests to compare objects, sadly phpunit has issue comparing objects, that's why
assertTrue()is hereFixed #18 to use
ltrim()with TODO and follow-up #3312079: Make output of \Drupal\Component\Utility\Variable::export() consistent on PHP 8.2+Comment #23
berdiras mentioned in slack, would love to have some input on this part, see also previous comment.
lets add a basic docblock to those three.
Comment #24
andypostfixed patch (without .orig files)
Re #23
1) already filed #3312079: Make output of \Drupal\Component\Utility\Variable::export() consistent on PHP 8.2+ to get rid of the TODO but we need to keep return value the same as it was as this is core API
2) added to
FakeRecordas theContainerAwareEventDispatcherTestis the copy from Symfony and should be kept inline with it https://github.com/symfony/symfony/blob/6.2/src/Symfony/Component/EventD... and follow-up should improve via #3312075: Make \Drupal\Tests\Component\EventDispatcher\ContainerAwareEventDispatcherTest more inline with Symfony 6.2Comment #25
andypostpatch for 9.5 to test
Comment #26
andypostuse faster comparison, thanks @alexpott
Comment #27
andypostAfter discussion at IRC with @alexpott - let's keep output to vary as it has mostly no usage and should mimic PHP dumping
Ref https://github.com/php/php-src/pull/8233
Comment #28
alexpottRe #27 - I think this change is correct for the same reasons that the upstream change is correct - see https://github.com/php/php-src/pull/8233 - this makes the code generated portable to working regardless of namespace the code is used it.
Comment #29
andypost\Drupal\Tests\views\Functional\TaxonomyGlossaryTestfixed with #3309748-17: Define missing object properties on non-testing classes for PHP 8.2Comment #30
andypostfor 9.5 patch this types should be removed, see #25 test run on PHP 7.3
Comment #31
andypostimproved comment for testing data with link to PHP issue, also here's 9.5.x patch
Comment #32
andypostRun without patch shows 20 failed tests https://www.drupal.org/pift-ci-job/2486875
Re-queued https://www.drupal.org/pift-ci-job/2486909 because first run shows 3 failed https://www.drupal.org/pift-ci-job/2486885
Comment #33
mondrakeassertSame?
assertNotSame?
assertSame?
assertNotSame?
typehint property?
typehint property?
typehint property?
Comment #34
andypostFixed #33 1-4 and 7 - the 5-6 are review from 9.5 patch
phpunit docs said it's ok to compare objects https://phpunit.readthedocs.io/en/9.5/assertions.html#assertsame
I messed up with https://github.com/sebastianbergmann/phpunit/issues/4707
uploading only 10.x patch as 9.5 will need extra clean-up
Comment #35
andypost1/4 passed, the most often failure is https://dispatcher.drupalci.org/job/drupal_patches/150721/testReport/jun...
Comment #36
andypostre-roll
Comment #37
andypostsqlite+php 8.2 queued now too, ref #3283449: Create a DrupalCI Environment for PHP 8.2
Comment #38
andypostLast core CI run PHP 8.2 + sqlite https://www.drupal.org/pift-ci-job/2490356
Comment #39
wim leersTesting with
👇
This test passes fine on PHP 8.2 without this change? 🤔
As does this test.
And this test…
Re-reading the issue summary, I see
See #3295821-91: Ignore: patch testing issue for PHP 8.2 attributesandUse classes instead of interfaces when creating mocks to make tests pass, but I don't yet see how I can reproduce those failures? 🤔🙈Comment #40
berdirAll those should result in deprecation messages. Make sure that you have deprecations enabled in your phpunit.xml, otherwise you might not see them.
Comment #41
wim leers#40 I literally can't get it to trigger deprecation errors…
If I run
\Drupal\Tests\contact\Unit\MailHandlerTestbut makecore/.deprecation-ignore.txtempty, I can see deprecation errors just fine.I really wonder what I'm doing wrong 🙈
Comment #42
andypostAdded to summary steps to reproduce
Last random failure should be fixed in #3315227: Drupal\Tests\views\FunctionalJavascript\Plugin\views\Handler\FilterTest is failing a lot at the moment
Comment #43
andypostLooks like now all tests are green, looking for reviews
Comment #44
taran2l1.
So, one
EntityBaseChildand twoEntityBaseTest. Is it on purpose?2. Taking another look at
EntityBaseclass, and it just uses undefined properties like $id, for example:So, mocking those via a test subclass just hides the real issue, no? Am I missing something or those properties belong to
EntityBase?Comment #45
andypostRe #44.1 yes, on purpose of inheritance, otherwise you'll get class already defined exception (from base test)
Interesting question #44.2 from
phpstanPOV but that's done on purpose because config and content classes using different approach to access properties (content entity using magic__get()for that)Comment #46
berdir> So, one EntityBaseChild and two EntityBaseTest. Is it on purpose?
The problem is that loading all test classes (which phpunit does by default) will result in duplicate test classes otherwise. It's OK to have two duplicates because they live in a different namespace. But for consistency (or non-consistency if you will) we could also give all 3 of them a unique class name.
> So, mocking those via a test subclass just hides the real issue, no?
There is no real issue here. Entity types are expected to define the properties that they are "defining" (they are defined as part of mocking the entity type definition). Since we mock directly from the base classes and not real entity types, they don't have properties defined, so we have to do it.
There is one notable exception, and that's the original property for one of them. We work around that for config entities with the special annotation to allow undefined properties, but this is not a config entity. (and content entities rely on magic for the same). We can remove that again once #2839195: Add a method to access the original property is in.
EntityBase::id() is kinda weird, but I believe it does not cause actual issues because it uses ??. Those methods should maybe be abstract/and/or use entity keys, config entities currently have to override that method if they use a different property for the id.
Comment #47
taran2lYup, like make them all the same or three totally different :)
Okay, but I think all of the four id/uuid/langcode/label are being used by EntityBase => thus imo they should be declared there. For me, it feels that 8.2 has just unhidden an issue here, and this code will hide it again.
Alternatively, EntityBase should be refactored to use entity keys (or do this in a follow-up)
Comment #48
berdirYes and no. EntityBase is weird. But even if we change it to use entity keys or abstract (which would be an API change for subclasses), we still need subclasses that define those because we need them for these tests and we would set it to the same keys as they are implicitly set to right now
As mentioned earlier, I'm no fan at all of these unit tests, they are not testing much and have to mock a metric ton of stuff to test the little things that they do. But that's for another day.
setting to needs work to have different test class names, lets use something that matches the test for each.
Comment #49
andypostLet's see the same name
Comment #51
andypostInteresting that this test fails only on PHP 8.1
Comment #52
longwaveI think #51 is because EntityBaseTest is declared twice in the same namespace:
Not sure why this isn't failing on PHP 8.2 though.
This test passes locally if I remove this entire block, which is the trigger for the deprecation:
Can we just remove this instead?
Otherwise all the changes look good. I reviewed the patch before reading all the comments and had the same question as @Taran2L about the EntityBase properties. I can see the argument both ways -
id()and friends probably should be abstract, but we can't easily change that now, so fixing the tests is the easier thing to do. I also agree that the unit tests are mocking way too much.Comment #53
longwaveAddressed #52; renamed the EntityUrlTest test entity, and removed what appears to be dead code from NodeOperationAccessTest.
Comment #54
andypostConfirm that
NodeOperationAccessTestno longer throws deprecation warning (even without patch)Comment #55
andypostI was wrong in previous comment, patch looks ready to go but I think @Berdir should RTBC it
Comment #56
wim leers🤔 Shouldn't this be set on
\Drupal\Core\TypedData\TypedDatainstead, to ensure allabstract class TypedDatasubclasses get it? To ensure contrib/custom subclasses are fixed too?See
\Drupal\Core\TypedData\TypedData::getValue()and the setter.It's pretty weird that these all define that property:
\Drupal\Core\Config\Schema\Element::$value\Drupal\Core\TypedData\Plugin\DataType\Any::$value\Drupal\Core\TypedData\PrimitiveBase::$value\Drupal\layout_builder\Plugin\DataType\SectionData::$value\Drupal\Tests\Core\Plugin\Fixtures\Plugin\DataType\TestDataType::$value(And that's just core.)
Ah … this is intentional:
… presumably to specify type hints with as narrowly a type as possible. 👍
ALL GOOD! ✅
🤯
🤔 Übernit: why these empty lines?
I don't think that last point should prevent this from getting committed 🤓 Leaving the RTBC honor to @Berdir, who knows this problem space far better 😊
Comment #57
longwaveRe #56.1 similar to the EntityBase properties discussed above, TypedData assumes
$this->valuefor convenience but you do not have to use it. For example EntityAdapter declares$entityinstead and overridesgetValue()to return it.Re #56.3 this is a PHPCS rule, without the blank lines you get
Comment #58
berdirAFAIK our coding standards requires an empty line before the closing } of a class, no? (crosspost with #57 which confirmed that)
I feel like I have worked a bit too much on this myself to RTBC, but others have reviewed it too including the parts that I did, so it's probably OK?
Comment #60
catchThis looks good to me, really nice to be all green before a stable release especially given the number of non-trivial changes to deal with in PHP 8.2
Committed/pushed to 10.1.x and cherry-picked to 9.5.x, thanks!