Problem/Motivation

Similarly to #3063887: Support PHPUnit 8 in Drupal 9, drop support for PHPUnit 7, this issue is about enabling testing with PHPUnit 9 in Drupal 9.

PHPUnit 7 support ended on February 7, 2020
PHPUnit 8 support ends on February 5, 2021
PHPUnit 9 support ends on February 4, 2022
PHPUnit 10 will be released in February, 2021.

In PHPUnit8 several assertions methods are deprecated for removal in PHPUnit9, for example:

  • Using assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringContainsString() or assertStringContainsStringIgnoringCase() instead.
  • The @expectedException, @expectedExceptionCode, @expectedExceptionMessage, and @expectedExceptionMessageRegExp annotations are deprecated. They will be removed in PHPUnit 9. Refactor your test to use expectException(), expectExceptionCode(), expectExceptionMessage(), or expectExceptionMessageRegExp() instead.
  • assertInternalType() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertIsArray(), assertIsBool(), assertIsFloat(), assertIsInt(), assertIsNumeric(), assertIsObject(), assertIsResource(), assertIsString(), assertIsScalar(), assertIsCallable(), or assertIsIterable() instead.
  • assertArraySubset() is deprecated and will be removed in PHPUnit 9.
  • getObjectAttribute() is deprecated and will be removed in PHPUnit 9.
  • readAttribute() is deprecated and will be removed in PHPUnit 9.

Also, some deprecations are thrown since we are currently using functionalities that PHPUnit is in the process of deprecating (for example, TestListeners, deprecated in PHPUnit8 but not removed from PHPUnit9).

The PHPUnit-bridge deprecation handler and #3116856: Workaround PHPUnit 8 warnings are silencing the warnings, currently. Spinoffs shall address the gaps and remove the silencing.

Spin offs:

Done:

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Comments

mondrake created an issue. See original summary.

mondrake’s picture

Issue tags: +PHPUnit 9
alexpott’s picture

Status: Postponed » Needs review
StatusFileSize
new43.37 KB
new57.45 KB

Let's see what breaks... interdiff to the patch in #3063887: Support PHPUnit 8 in Drupal 9, drop support for PHPUnit 7

Status: Needs review » Needs work

The last submitted patch, 3: 3110543-3.patch, failed testing. View results

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new284.21 KB

Patch in #3 combined with patches from the spun-off issues

mondrake’s picture

StatusFileSize
new284.75 KB
new549 bytes
mondrake’s picture

mondrake’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 7: 3110543-7.patch, failed testing. View results

longwave’s picture

Title: Support PHPUnit 9 in Drupal 9 » [meta] Support PHPUnit 9 in Drupal 9
Category: Task » Plan
Status: Needs work » Active

Repurposing this as a meta as suggested by @alexpott in #3108006: Replace assertInternalType() calls with dedicated methods

alexpott’s picture

We should work out what we're doing for assertArraySubset - if you run core/tests/Drupal/KernelTests/Core/Action/SaveActionTest.php on D9 with -v you get warnings.

voleger’s picture

Issue summary: View changes

Updated dates in IS

berdir’s picture

assertArraySubset: In https://github.com/sebastianbergmann/phpunit/issues/3494, someone created a separate package, but that's PHPUnit 9 only and doesn't help to get rid of the deprecation messages :-/

berdir’s picture

So if I understand that correctly, per https://www.drupal.org/pift-ci-job/1587117, phpunit is currently writing out lots of warnings about its own deprecations and we ignore them unless these tests actually fail in a different way too.

I think the first step would be to improve run-tests.sh to fail on that and fix that? For BC, we could see if can do our own deprecation instead in overridden methods that we can control.

That's also what @mondrake meant in #3063887-93: Support PHPUnit 8 in Drupal 9, drop support for PHPUnit 7. It's not "travis stuff", it's core stuff, we're simply ignoring it right now.

berdir’s picture

Status: Active » Needs review
StatusFileSize
new1.04 KB

As a quick hack, just letting all tests with warnings fail, to see how bad it is.

Status: Needs review » Needs work

The last submitted patch, 16: 3110543-report-warnings-16.patch, failed testing. View results

longwave’s picture

Both #3108006: Replace assertInternalType() calls with dedicated methods and #3113077: Replace assertContains() on strings with assertStringContainsString() or assertStringContainsStringIgnoringCase() are disruptive to Drupal 8.8/8.9/9.0 test compatibility as the replacement methods aren't available in PHPUnit 6, which is the minimum version for Drupal 8.8. We either need to add forward compatibility shims to Drupal 8.8/8.9 so we can use the newer methods, or I think we have to bump this to 9.1?

berdir’s picture

Drupal 8 doesn't support PHPUnit 8 I think, so isn't bothered by those deprecations in the first place?

I think it's fine to do these replacements only in 9.0.

longwave’s picture

But we want to be able to easily port patches between 8.9 and 9.0, so changing this in 9.0 only makes that more difficult.

berdir’s picture

That's true, but removing deprecations does make that harder too for example :) I think 9.0 vs 9.1 is up to to framework/release managers at this point, I originally thought it's better to wait for 9.1 with these changes and also the return type, but I think these warnings are going to be very confusing when running tests manually and it might be worth the extra overhead of keeping patches in sync. The 9.1 branch might open as early as march from what I know, so we'll need 9.1 compatible patches from then on anyway.

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new6.09 KB

How about adding a forward compatibility layer for now - so we don't trigger the warnings and then we can fix later in D9. We could copy the PHPUnit 8 methods to our code and remove the warnings.

Here's a pragmatic approach - we can ignore the warnings. In the future we can change the warnings into our deprecations and remove usage from core but not when we're trying to make D8 and D9 cross compatibility easy.

Status: Needs review » Needs work

The last submitted patch, 22: 3110543-2-21.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new461 bytes
new16.94 KB
new21.61 KB
+++ b/core/lib/Drupal/Core/Test/PhpUnitTestRunner.php
@@ -209,14 +209,14 @@ public function runTests($test_id, array $unescaped_test_classnames, &$status =
-    if ($status == TestStatus::PASS) {
+    if ($status == TestStatus::PASS && strpos(implode('', $output), 'WARNINGS') === FALSE) {

So this is a bit brittle because we'll get into a problem with test classes that contain the work WARNINGS :). Fortunately we can get PHPUnit to convert the warnings to errors for us and therefore be a bit more strict. Yay.

The approach I've followed for fixing the component unit tests is as follows - I've fixed the tests as these don't change much - but I've used the trait for the composer tests because this array is under active development and using the trait is likely to make things a bit simpler.

alexpott’s picture

StatusFileSize
new3.71 KB
new21.68 KB

A little neater.

longwave’s picture

  1. +++ b/core/tests/Drupal/Tests/Component/Annotation/Doctrine/DocParserTest.php
    @@ -702,7 +702,7 @@ public function testAnnotationWithRequiredAttributesWithoutContructor()
    +            $this->assertStringContainsString('Attribute "value" of @Drupal\Tests\Component\Annotation\Doctrine\Fixtures\AnnotationWithRequiredAttributesWithoutContructor declared on property SomeClassName::invalidProperty. expects a(n) string. This value should not be null.', $exc->getMessage());
    
    @@ -1145,7 +1145,7 @@ public function testCastInt()
    +        $this->assertIsInt($annot->foo);
    

    How will we backport these to Drupal 8/PHPUnit 6, as these tests directly extend TestCase but these new methods don't exist in PHPUnit 6? Or will we just change these components in 9.x only?

  2. +++ b/core/tests/Drupal/Tests/Traits/PHPUnit8Warnings.php
    @@ -0,0 +1,50 @@
    +   * Ignores specific PHPUNit 8 warnings.
    

    Nitpick: PHPUNit -> PHPUnit

alexpott’s picture

@longwave none of this is intended for backport. I think it is ok if this component test diverges a bit - it's not like it changes alot. And the people we really want to help is contrib - so they can maintain tests on both D8 and D9 without that much complexity. Apply this patch to D9 achieves that.

The last submitted patch, 24: 3110543-2-23.patch, failed testing. View results

The last submitted patch, 24: 3110543-2-23.test-only.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 25: 3110543-2-25.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new948 bytes
new21.9 KB

Status: Needs review » Needs work

The last submitted patch, 31: 3110543-2-31.patch, failed testing. View results

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new5.52 KB
new27.42 KB

Hopefully green.

alexpott’s picture

I've split #33 out into a critical sub-issue as it really is about PHPUnit8 and not PHPUnit9. See #3116856: Workaround PHPUnit 8 warnings

mondrake’s picture

At least for #3108006: Replace assertInternalType() calls with dedicated methods and #3113077: Replace assertContains() on strings with assertStringContainsString() or assertStringContainsStringIgnoringCase(), we could add to Drupal 8 only a tiny FC shim to allow backporting easily test changes from D9.

For example, overriding assertInternalType and redirecting it to the more accurate assertion method if it is available. In D9 it will not be necessary.

EDIT - sorry I meant the other way round:

For example, implementing assertIsInt and redirecting it to assertInternalType('int', ...) in case the accurate assertion method is not available. In D9 it will not be necessary.

mondrake’s picture

Status: Needs review » Active

This is a meta now, no patches expected.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
daffie’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes

Filed #3127141: Use PHPUnit 9 for PHP 7.4+, while keeping support for PHPUnit 8.4 in PHP 7.3. We're not that far from being able to support PHPUnit 9 now. We basically only miss the remaining issues to replace the usage of reflection-enabled PHPUnit methods, plus silencing the new warnings actually being added in PHPUnit 9.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Aki Tendo’s picture

Once this is complete any tests working with the assert statement can be configured not to run if assertions are turned off using the requires setting annotation.

I'm puzzled as to why this hasn't been added to the documentation for PHP Unit. Mr. Bergmann did the pull over 2 years ago. This feature was written by me specifically for when we switched over to handle this circumstance. Anyway, I checked the codebase of PHPUnit, both 8.5 and 9.1 have the code necessary to honor setting annotations.

/**
 * @requires setting zend.assertions 1
 */

That will cause the test to skip if assertions are turned off, useful for the tests in place to make sure runtime assertions are thrown when they should be. Conversely -1 can be used to skip the test if assertions are turned on.

Assertions aren't the only ini directive this can test for - any ini directive is fair game.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
mondrake’s picture

Issue summary: View changes
tr’s picture

Why are we failing and aborting tests on DrupalCI that use a method that's *deprecated* in PHPUnit 8? These are still valid methods, PHPUnit 8 is still in use on DrupalCI. These should not cause a test fail. Instead they should be handled like methods in Drupal that are deprecated - tests should pass.

The PHPUnit-bridge deprecation handler and #3116856: Workaround PHPUnit 8 warnings are silencing the warnings, currently.

That's not true, at least for contrib.

It is not acceptable to fail tests running with PHPUnit 8 on DrupalCI just because of one method that will be removed in PHPUnit 9. Give me a notice if you want, or let me run deprecation checks myself like we do for all other deprecations, but failing the tests and forcing me to immediately change my code is wrong - If PHPUnit 8 is still supported, then you must support it.

See https://www.drupal.org/node/2632588/qa for the failure.

mondrake’s picture

Issue summary: View changes
Status: Active » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.