From 74fbb0aabdee3e1a5da7b8e489a725afdc5824fd Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Tue, 13 Oct 2020 10:14:35 +0100
Subject: [PATCH] Issue #3127141 by mondrake, longwave, alexpott, Neslee Canil
 Pinto, Suresh Prabhu Parkala, ravi.shankar: Use PHPUnit 9 for PHP 7.4+, while
 keeping support for PHPUnit 8.4 in PHP 7.3

---
 composer.json                                 |  7 ++-
 composer.lock                                 |  2 +-
 .../Metapackage/DevDependencies/composer.json |  2 +-
 core/lib/Drupal/Core/Composer/Composer.php    |  4 +-
 .../Kernel/EntityTranslationNormalizeTest.php |  4 +-
 .../tests/src/Unit/MigrateStubTest.php        |  4 +-
 ...ityReferenceSelectionReferenceableTest.php |  2 +-
 core/scripts/run-tests.sh                     |  2 +-
 .../BuildTests/Framework/BuildTestBase.php    |  2 +
 .../Core/Config/ConfigImporterTest.php        |  4 +-
 .../KernelTests/Core/File/NameMungingTest.php |  2 +-
 .../Core/Messenger/MessengerTest.php          |  2 +-
 .../Drupal/KernelTests/KernelTestBase.php     |  2 +
 .../PhpUnit8/TestCompatibilityTrait.php       | 10 +++
 .../PhpUnit9/TestCompatibilityTrait.php       | 14 +++++
 core/tests/Drupal/Tests/BrowserTestBase.php   |  1 +
 .../AnnotationBridgeDecoratorTest.php         |  3 +
 .../DependencyInjection/ContainerTest.php     |  3 +
 .../Dumper/OptimizedPhpArrayDumperTest.php    |  3 +
 .../Component/Diff/Engine/DiffOpTest.php      |  3 +-
 .../Component/Gettext/PoStreamWriterTest.php  |  3 +
 .../Component/PhpStorage/FileStorageTest.php  |  8 ++-
 .../Plugin/PluginManagerBaseTest.php          |  3 +
 .../Plugin/VendorHardening/ConfigTest.php     |  3 +
 .../VendorHardeningPluginTest.php             |  5 ++
 .../Drupal/Tests/ComposerIntegrationTest.php  |  6 ++
 .../Asset/CssCollectionGrouperUnitTest.php    | 12 ++--
 .../Listeners/DeprecationListenerTrait.php    | 11 ++++
 .../Tests/Listeners/HtmlOutputPrinter.php     | 16 ++++-
 .../Tests/PhpUnitCompatibilityTrait.php       | 21 +++++++
 .../Drupal/Tests/PhpUnitWarningsTest.php      | 61 ++++++++++++++-----
 .../Drupal/Tests/Traits/PhpUnitWarnings.php   | 10 +++
 core/tests/Drupal/Tests/UnitTestCase.php      |  1 +
 33 files changed, 193 insertions(+), 43 deletions(-)
 create mode 100644 core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit8/TestCompatibilityTrait.php
 create mode 100644 core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit9/TestCompatibilityTrait.php
 create mode 100644 core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php

diff --git a/composer.json b/composer.json
index 8da852da9288..6192b0ab500c 100644
--- a/composer.json
+++ b/composer.json
@@ -21,7 +21,7 @@
         "composer/composer": "^1.9.1",
         "drupal/coder": "^8.3.7",
         "mikey179/vfsstream": "^1.6.8",
-        "phpunit/phpunit": "^8.4.1",
+        "phpunit/phpunit": "^8.4.1 || ^9",
         "phpspec/prophecy": "^1.7",
         "symfony/css-selector": "^4.4",
         "symfony/phpunit-bridge": "^5.1.4",
@@ -93,7 +93,10 @@
         "pre-update-cmd": "Drupal\\Composer\\Composer::ensureComposerVersion",
         "pre-autoload-dump": "Drupal\\Core\\Composer\\Composer::preAutoloadDump",
         "drupal-phpunit-upgrade-check": "Drupal\\Core\\Composer\\Composer::upgradePHPUnit",
-        "drupal-phpunit-upgrade": "@composer update phpunit/phpunit symfony/phpunit-bridge phpspec/prophecy symfony/yaml --with-dependencies --no-progress",
+        "drupal-phpunit-upgrade": [
+            "@composer update phpunit/phpunit --with-dependencies --no-progress",
+            "@composer require phpspec/prophecy-phpunit:^2 --no-progress --no-suggest"
+        ],
         "post-update-cmd": [
             "Drupal\\Composer\\Composer::generateMetapackages"
         ],
diff --git a/composer.lock b/composer.lock
index 7654dfbdb221..cd026c8142ca 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "059e8aee61edb73b1526b840eb6c624c",
+    "content-hash": "09de613d0e44689de15282c33d3d700e",
     "packages": [
         {
             "name": "asm89/stack-cors",
diff --git a/composer/Metapackage/DevDependencies/composer.json b/composer/Metapackage/DevDependencies/composer.json
index b6de7308ab55..ace515f39386 100644
--- a/composer/Metapackage/DevDependencies/composer.json
+++ b/composer/Metapackage/DevDependencies/composer.json
@@ -16,7 +16,7 @@
         "justinrainbow/json-schema": "^5.2",
         "mikey179/vfsstream": "^1.6.8",
         "phpspec/prophecy": "^1.7",
-        "phpunit/phpunit": "^8.4.1",
+        "phpunit/phpunit": "^8.4.1 || ^9",
         "symfony/browser-kit": "^4.4",
         "symfony/css-selector": "^4.4",
         "symfony/dom-crawler": "^4.4 !=4.4.5",
diff --git a/core/lib/Drupal/Core/Composer/Composer.php b/core/lib/Drupal/Core/Composer/Composer.php
index 6b7d5899d6e0..2f60ab9d0fc7 100644
--- a/core/lib/Drupal/Core/Composer/Composer.php
+++ b/core/lib/Drupal/Core/Composer/Composer.php
@@ -310,7 +310,7 @@ public static function upgradePHPUnit(Event $event) {
       return;
     }
 
-    // If the PHP version is 7.3 or above and PHPUnit is less than version 7
+    // If the PHP version is 7.4 or above and PHPUnit is less than version 9
     // call the drupal-phpunit-upgrade script to upgrade PHPUnit.
     if (!static::upgradePHPUnitCheck($phpunit_package->getVersion())) {
       $event->getComposer()
@@ -332,7 +332,7 @@ public static function upgradePHPUnit(Event $event) {
    *   TRUE if the PHPUnit needs to be upgraded, FALSE if not.
    */
   public static function upgradePHPUnitCheck($phpunit_version) {
-    return !(version_compare(PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, '7.3') >= 0 && version_compare($phpunit_version, '7.0') < 0);
+    return !(version_compare(PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, '7.4') >= 0 && version_compare($phpunit_version, '9.0') < 0);
   }
 
 }
diff --git a/core/modules/hal/tests/src/Kernel/EntityTranslationNormalizeTest.php b/core/modules/hal/tests/src/Kernel/EntityTranslationNormalizeTest.php
index bd31f529cc47..af1f10a22caa 100644
--- a/core/modules/hal/tests/src/Kernel/EntityTranslationNormalizeTest.php
+++ b/core/modules/hal/tests/src/Kernel/EntityTranslationNormalizeTest.php
@@ -70,8 +70,8 @@ public function testNodeTranslation() {
 
     $normalized = $this->serializer->normalize($node, $this->format);
 
-    $this->assertContains(['lang' => 'en', 'value' => $node->getTitle()], $normalized['title'], 'Original language title has been normalized.');
-    $this->assertContains(['lang' => 'de', 'value' => $translation->getTitle()], $normalized['title'], 'Translation language title has been normalized.');
+    $this->assertContainsEquals(['lang' => 'en', 'value' => $node->getTitle()], $normalized['title'], 'Original language title has been normalized.');
+    $this->assertContainsEquals(['lang' => 'de', 'value' => $translation->getTitle()], $normalized['title'], 'Translation language title has been normalized.');
 
     /** @var \Drupal\node\NodeInterface $denormalized_node */
     $denormalized_node = $this->serializer->denormalize($normalized, 'Drupal\node\Entity\Node', $this->format);
diff --git a/core/modules/migrate/tests/src/Unit/MigrateStubTest.php b/core/modules/migrate/tests/src/Unit/MigrateStubTest.php
index fcf171b17c42..4a68dfdffc69 100644
--- a/core/modules/migrate/tests/src/Unit/MigrateStubTest.php
+++ b/core/modules/migrate/tests/src/Unit/MigrateStubTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\migrate\Unit;
 
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Tests\UnitTestCase;
 use Drupal\migrate\MigrateStub;
 use Drupal\migrate\Plugin\MigrateDestinationInterface;
 use Drupal\migrate\Plugin\MigrateIdMapInterface;
@@ -10,7 +11,6 @@
 use Drupal\migrate\Plugin\MigrationInterface;
 use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
 use Drupal\migrate\Row;
-use PHPUnit\Framework\TestCase;
 use Prophecy\Argument;
 
 /**
@@ -20,7 +20,7 @@
  *
  * @coversDefaultClass \Drupal\migrate\MigrateStub
  */
-class MigrateStubTest extends TestCase {
+class MigrateStubTest extends UnitTestCase {
 
   /**
    * The plugin manager prophecy.
diff --git a/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php b/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
index 16b98105353a..a4bea10bdfe7 100644
--- a/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
+++ b/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
@@ -126,7 +126,7 @@ public function testReferenceablesWithNoLabelKey($match, $match_operator, $limit
       // entity labels.
       // @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface::getReferenceableEntities()
       $item = is_string($item) ? Html::escape($item) : $item;
-      $this->assertContains($item, $referenceables[$this->bundle]);
+      $this->assertContainsEquals($item, $referenceables[$this->bundle]);
     }
 
     // Test ::countReferenceableEntities().
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 955eb5bf55b0..91b47782610a 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -149,7 +149,7 @@
 }
 
 if (!Composer::upgradePHPUnitCheck(Version::id())) {
-  simpletest_script_print_error("PHPUnit testing framework version 7 or greater is required when running on PHP 7.3 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.");
+  simpletest_script_print_error("PHPUnit testing framework version 9 or greater is required when running on PHP 7.4 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.");
   exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
 }
 
diff --git a/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php b/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php
index 7bd4f7034714..898aa582beb7 100644
--- a/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php
+++ b/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php
@@ -7,6 +7,7 @@
 use Behat\Mink\Mink;
 use Behat\Mink\Session;
 use Drupal\Component\FileSystem\FileSystem as DrupalFilesystem;
+use Drupal\Tests\PhpUnitCompatibilityTrait;
 use Drupal\Tests\Traits\PhpUnitWarnings;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
@@ -53,6 +54,7 @@ abstract class BuildTestBase extends TestCase {
 
   use ExternalCommandRequirementsTrait;
   use PhpUnitWarnings;
+  use PhpUnitCompatibilityTrait;
 
   /**
    * The working directory where this test will manipulate files.
diff --git a/core/tests/Drupal/KernelTests/Core/Config/ConfigImporterTest.php b/core/tests/Drupal/KernelTests/Core/Config/ConfigImporterTest.php
index 1e6c1b3ead32..e5925e810046 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/ConfigImporterTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigImporterTest.php
@@ -612,7 +612,7 @@ public function testUnmetDependency() {
         'Configuration <em class="placeholder">unknown.config</em> depends on the <em class="placeholder">unknown</em> extension that will not be installed after import.',
       ];
       foreach ($expected as $expected_message) {
-        $this->assertContains($expected_message, $error_log, $expected_message);
+        $this->assertContainsEquals($expected_message, $error_log, $expected_message);
       }
     }
 
@@ -658,7 +658,7 @@ public function testUnmetDependency() {
         'Configuration <em class="placeholder">config_test.dynamic.dotted.theme</em> depends on themes (<em class="placeholder">unknown, Seven</em>) that will not be installed after import.',
       ];
       foreach ($expected as $expected_message) {
-        $this->assertContains($expected_message, $error_log, $expected_message);
+        $this->assertContainsEquals($expected_message, $error_log, $expected_message);
       }
     }
   }
diff --git a/core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php b/core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
index 1e97b7a805a0..991f9263c9bd 100644
--- a/core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
+++ b/core/tests/Drupal/KernelTests/Core/File/NameMungingTest.php
@@ -42,7 +42,7 @@ public function testMunging() {
     $munged_name = file_munge_filename($this->name, '', TRUE);
     $messages = \Drupal::messenger()->all();
     \Drupal::messenger()->deleteAll();
-    $this->assertContains(strtr('For security reasons, your upload has been renamed to <em class="placeholder">%filename</em>.', ['%filename' => $munged_name]), $messages['status'], 'Alert properly set when a file is renamed.');
+    $this->assertContainsEquals(strtr('For security reasons, your upload has been renamed to <em class="placeholder">%filename</em>.', ['%filename' => $munged_name]), $messages['status'], 'Alert properly set when a file is renamed.');
     $this->assertNotEqual($munged_name, $this->name, new FormattableMarkup('The new filename (%munged) has been modified from the original (%original)', ['%munged' => $munged_name, '%original' => $this->name]));
   }
 
diff --git a/core/tests/Drupal/KernelTests/Core/Messenger/MessengerTest.php b/core/tests/Drupal/KernelTests/Core/Messenger/MessengerTest.php
index ac305022ff30..e244e05e044c 100644
--- a/core/tests/Drupal/KernelTests/Core/Messenger/MessengerTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Messenger/MessengerTest.php
@@ -49,7 +49,7 @@ public function testRemoveSingleMessage() {
 
     // Check we only have the second one.
     $this->assertCount(1, $this->messenger->messagesByType(MessengerInterface::TYPE_STATUS));
-    $this->assertContains('Second message with <em>markup!</em> (not removed).', $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS));
+    $this->assertContainsEquals('Second message with <em>markup!</em> (not removed).', $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS));
 
   }
 
diff --git a/core/tests/Drupal/KernelTests/KernelTestBase.php b/core/tests/Drupal/KernelTests/KernelTestBase.php
index 88c956b661b3..86644ee69e35 100644
--- a/core/tests/Drupal/KernelTests/KernelTestBase.php
+++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
@@ -18,6 +18,7 @@
 use Drupal\Core\Test\TestDatabase;
 use Drupal\Tests\ConfigTestTrait;
 use Drupal\Tests\RandomGeneratorTrait;
+use Drupal\Tests\PhpUnitCompatibilityTrait;
 use Drupal\Tests\TestRequirementsTrait;
 use Drupal\Tests\Traits\PhpUnitWarnings;
 use Drupal\TestTools\Comparator\MarkupInterfaceComparator;
@@ -79,6 +80,7 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
   use ConfigTestTrait;
   use TestRequirementsTrait;
   use PhpUnitWarnings;
+  use PhpUnitCompatibilityTrait;
 
   /**
    * {@inheritdoc}
diff --git a/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit8/TestCompatibilityTrait.php b/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit8/TestCompatibilityTrait.php
new file mode 100644
index 000000000000..9beee7d0a198
--- /dev/null
+++ b/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit8/TestCompatibilityTrait.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\TestTools\PhpUnitCompatibility\PhpUnit8;
+
+/**
+ * Drupal's forward compatibility layer with multiple versions of PHPUnit.
+ */
+trait TestCompatibilityTrait {
+
+}
diff --git a/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit9/TestCompatibilityTrait.php b/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit9/TestCompatibilityTrait.php
new file mode 100644
index 000000000000..29be2acbec8b
--- /dev/null
+++ b/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit9/TestCompatibilityTrait.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\TestTools\PhpUnitCompatibility\PhpUnit9;
+
+use Prophecy\PhpUnit\ProphecyTrait;
+
+/**
+ * Drupal's forward compatibility layer with multiple versions of PHPUnit.
+ */
+trait TestCompatibilityTrait {
+
+  use ProphecyTrait;
+
+}
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index 448bb6a22b60..73aeb23d3f11 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -65,6 +65,7 @@ abstract class BrowserTestBase extends TestCase {
   }
   use XdebugRequestTrait;
   use PhpUnitWarnings;
+  use PhpUnitCompatibilityTrait;
 
   /**
    * The database prefix of this test run.
diff --git a/core/tests/Drupal/Tests/Component/Annotation/Plugin/Discovery/AnnotationBridgeDecoratorTest.php b/core/tests/Drupal/Tests/Component/Annotation/Plugin/Discovery/AnnotationBridgeDecoratorTest.php
index 12732e110ace..324eab95b4bd 100644
--- a/core/tests/Drupal/Tests/Component/Annotation/Plugin/Discovery/AnnotationBridgeDecoratorTest.php
+++ b/core/tests/Drupal/Tests/Component/Annotation/Plugin/Discovery/AnnotationBridgeDecoratorTest.php
@@ -6,6 +6,7 @@
 use Drupal\Component\Annotation\Plugin\Discovery\AnnotationBridgeDecorator;
 use Drupal\Component\Plugin\Definition\PluginDefinition;
 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Tests\PhpUnitCompatibilityTrait;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -14,6 +15,8 @@
  */
 class AnnotationBridgeDecoratorTest extends TestCase {
 
+  use PhpUnitCompatibilityTrait;
+
   /**
    * @covers ::getDefinitions
    */
diff --git a/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php b/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
index f348b0705b60..481827488467 100644
--- a/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
+++ b/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Component\DependencyInjection;
 
 use Drupal\Component\Utility\Crypt;
+use Drupal\Tests\PhpUnitCompatibilityTrait;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
@@ -24,6 +25,8 @@
  */
 class ContainerTest extends TestCase {
 
+  use PhpUnitCompatibilityTrait;
+
   /**
    * The tested container.
    *
diff --git a/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php b/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php
index 92ee5490acbe..5785aed465bb 100644
--- a/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php
+++ b/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Component\DependencyInjection\Dumper {
 
   use Drupal\Component\Utility\Crypt;
+  use Drupal\Tests\PhpUnitCompatibilityTrait;
   use PHPUnit\Framework\TestCase;
   use Symfony\Component\DependencyInjection\Definition;
   use Symfony\Component\DependencyInjection\Reference;
@@ -24,6 +25,8 @@
    */
   class OptimizedPhpArrayDumperTest extends TestCase {
 
+    use PhpUnitCompatibilityTrait;
+
     /**
      * The container builder instance.
      *
diff --git a/core/tests/Drupal/Tests/Component/Diff/Engine/DiffOpTest.php b/core/tests/Drupal/Tests/Component/Diff/Engine/DiffOpTest.php
index be2054811ea9..76f0064e7d96 100644
--- a/core/tests/Drupal/Tests/Component/Diff/Engine/DiffOpTest.php
+++ b/core/tests/Drupal/Tests/Component/Diff/Engine/DiffOpTest.php
@@ -4,7 +4,6 @@
 
 use Drupal\Component\Diff\Engine\DiffOp;
 use PHPUnit\Framework\TestCase;
-use PHPUnit\Framework\Error\Error;
 
 /**
  * Test DiffOp base class.
@@ -25,7 +24,7 @@ class DiffOpTest extends TestCase {
    * @covers ::reverse
    */
   public function testReverse() {
-    $this->expectException(Error::class);
+    $this->expectError();
     $op = new DiffOp();
     $result = $op->reverse();
   }
diff --git a/core/tests/Drupal/Tests/Component/Gettext/PoStreamWriterTest.php b/core/tests/Drupal/Tests/Component/Gettext/PoStreamWriterTest.php
index 39cf95d18aa2..47644dd2300b 100644
--- a/core/tests/Drupal/Tests/Component/Gettext/PoStreamWriterTest.php
+++ b/core/tests/Drupal/Tests/Component/Gettext/PoStreamWriterTest.php
@@ -4,6 +4,7 @@
 
 use Drupal\Component\Gettext\PoItem;
 use Drupal\Component\Gettext\PoStreamWriter;
+use Drupal\Tests\PhpUnitCompatibilityTrait;
 use org\bovigo\vfs\vfsStream;
 use org\bovigo\vfs\vfsStreamFile;
 use PHPUnit\Framework\TestCase;
@@ -14,6 +15,8 @@
  */
 class PoStreamWriterTest extends TestCase {
 
+  use PhpUnitCompatibilityTrait;
+
   /**
    * The PO writer object under test.
    *
diff --git a/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php b/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php
index 6230bdbd7ba6..c17b1bb516d0 100644
--- a/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php
+++ b/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php
@@ -4,8 +4,8 @@
 
 use Drupal\Component\PhpStorage\FileStorage;
 use Drupal\Component\Utility\Random;
+use Drupal\Tests\Traits\PhpUnitWarnings;
 use org\bovigo\vfs\vfsStreamDirectory;
-use PHPUnit\Framework\Error\Warning;
 
 /**
  * @coversDefaultClass \Drupal\Component\PhpStorage\FileStorage
@@ -14,6 +14,8 @@
  */
 class FileStorageTest extends PhpStorageTestBase {
 
+  use PhpUnitWarnings;
+
   /**
    * Standard test settings to pass to storage instances.
    *
@@ -99,8 +101,8 @@ public function testCreateDirectoryFailWarning() {
       'bin' => 'test',
     ]);
     $code = "<?php\n echo 'here';";
-    $this->expectException(Warning::class);
-    $this->expectExceptionMessage('mkdir(): Permission Denied');
+    $this->expectWarning();
+    $this->expectWarningMessage('mkdir(): Permission Denied');
     $storage->save('subdirectory/foo.php', $code);
   }
 
diff --git a/core/tests/Drupal/Tests/Component/Plugin/PluginManagerBaseTest.php b/core/tests/Drupal/Tests/Component/Plugin/PluginManagerBaseTest.php
index 954ff70110c9..e8192fcac5a5 100644
--- a/core/tests/Drupal/Tests/Component/Plugin/PluginManagerBaseTest.php
+++ b/core/tests/Drupal/Tests/Component/Plugin/PluginManagerBaseTest.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
 use Drupal\Component\Plugin\Mapper\MapperInterface;
 use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Tests\PhpUnitCompatibilityTrait;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -13,6 +14,8 @@
  */
 class PluginManagerBaseTest extends TestCase {
 
+  use PhpUnitCompatibilityTrait;
+
   /**
    * A callback method for mocking FactoryInterface objects.
    */
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php
index 9755278b512c..f800cdd5262a 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php
@@ -4,6 +4,7 @@
 
 use Composer\Package\RootPackageInterface;
 use Drupal\Composer\Plugin\VendorHardening\Config;
+use Drupal\Tests\Traits\PhpUnitWarnings;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -12,6 +13,8 @@
  */
 class ConfigTest extends TestCase {
 
+  use PhpUnitWarnings;
+
   /**
    * @covers ::getPathsForPackage
    */
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php
index 845356f887e9..3e130ba389bd 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php
@@ -8,6 +8,8 @@
 use Composer\Package\RootPackageInterface;
 use Drupal\Composer\Plugin\VendorHardening\Config;
 use Drupal\Composer\Plugin\VendorHardening\VendorHardeningPlugin;
+use Drupal\Tests\PhpUnitCompatibilityTrait;
+use Drupal\Tests\Traits\PhpUnitWarnings;
 use org\bovigo\vfs\vfsStream;
 use PHPUnit\Framework\TestCase;
 
@@ -17,6 +19,9 @@
  */
 class VendorHardeningPluginTest extends TestCase {
 
+  use PhpUnitWarnings;
+  use PhpUnitCompatibilityTrait;
+
   public function setUp(): void {
     parent::setUp();
     vfsStream::setup('vendor', NULL, [
diff --git a/core/tests/Drupal/Tests/ComposerIntegrationTest.php b/core/tests/Drupal/Tests/ComposerIntegrationTest.php
index 5cd2719bebf4..d74cf4202782 100644
--- a/core/tests/Drupal/Tests/ComposerIntegrationTest.php
+++ b/core/tests/Drupal/Tests/ComposerIntegrationTest.php
@@ -5,6 +5,7 @@
 use Drupal\Composer\Plugin\VendorHardening\Config;
 use Drupal\Core\Composer\Composer;
 use Drupal\Tests\Composer\ComposerIntegrationTrait;
+use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
 use Symfony\Component\Yaml\Yaml;
 
 /**
@@ -260,6 +261,11 @@ public function testVendorCleanup($class, $property) {
     $reflection = new \ReflectionProperty($class, $property);
     $reflection->setAccessible(TRUE);
     $config = $reflection->getValue();
+    // PHPUnit 9.5.3 removes 'phpunit/php-token-stream' from its dependencies.
+    // @todo remove the check below when PHPUnit 9 is the minimum.
+    if (RunnerVersion::getMajor() >= 9) {
+      unset($config['phpunit/php-token-stream']);
+    }
     foreach (array_keys($config) as $package) {
       $this->assertContains(strtolower($package), $packages);
     }
diff --git a/core/tests/Drupal/Tests/Core/Asset/CssCollectionGrouperUnitTest.php b/core/tests/Drupal/Tests/Core/Asset/CssCollectionGrouperUnitTest.php
index 7e5fe84836be..40efadf4ea43 100644
--- a/core/tests/Drupal/Tests/Core/Asset/CssCollectionGrouperUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Asset/CssCollectionGrouperUnitTest.php
@@ -113,8 +113,8 @@ public function testGrouper() {
     $this->assertSame('all', $group['media']);
     $this->assertTrue($group['preprocess']);
     $this->assertCount(3, $group['items']);
-    $this->assertContains($css_assets['system.base.css'], $group['items']);
-    $this->assertContains($css_assets['js.module.css'], $group['items']);
+    $this->assertContainsEquals($css_assets['system.base.css'], $group['items']);
+    $this->assertContainsEquals($css_assets['js.module.css'], $group['items']);
 
     // Check group 2.
     $group = $groups[1];
@@ -123,7 +123,7 @@ public function testGrouper() {
     $this->assertSame('all', $group['media']);
     $this->assertTrue($group['preprocess']);
     $this->assertCount(1, $group['items']);
-    $this->assertContains($css_assets['field.css'], $group['items']);
+    $this->assertContainsEquals($css_assets['field.css'], $group['items']);
 
     // Check group 3.
     $group = $groups[2];
@@ -132,7 +132,7 @@ public function testGrouper() {
     $this->assertSame('all', $group['media']);
     $this->assertTrue($group['preprocess']);
     $this->assertCount(1, $group['items']);
-    $this->assertContains($css_assets['external.css'], $group['items']);
+    $this->assertContainsEquals($css_assets['external.css'], $group['items']);
 
     // Check group 4.
     $group = $groups[3];
@@ -141,7 +141,7 @@ public function testGrouper() {
     $this->assertSame('all', $group['media']);
     $this->assertTrue($group['preprocess']);
     $this->assertCount(1, $group['items']);
-    $this->assertContains($css_assets['elements.css'], $group['items']);
+    $this->assertContainsEquals($css_assets['elements.css'], $group['items']);
 
     // Check group 5.
     $group = $groups[4];
@@ -150,7 +150,7 @@ public function testGrouper() {
     $this->assertSame('print', $group['media']);
     $this->assertTrue($group['preprocess']);
     $this->assertCount(1, $group['items']);
-    $this->assertContains($css_assets['print.css'], $group['items']);
+    $this->assertContainsEquals($css_assets['print.css'], $group['items']);
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php
index 3c2bb0bbae6e..6ef3a4fd8f13 100644
--- a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php
+++ b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php
@@ -132,6 +132,17 @@ public static function getSkippedDeprecations() {
       'AssertLegacyTrait::assertFieldByXPath() is deprecated in drupal:8.3.0 and is removed from drupal:10.0.0. Use $this->xpath() instead and check the values directly in the test. See https://www.drupal.org/node/3129738',
       'AssertLegacyTrait::assertNoFieldByXPath() is deprecated in drupal:8.3.0 and is removed from drupal:10.0.0. Use $this->xpath() instead and assert that the result is empty. See https://www.drupal.org/node/3129738',
       'AssertLegacyTrait::assertFieldsByValue() is deprecated in drupal:8.3.0 and is removed from drupal:10.0.0. Use iteration over the fields yourself instead and directly check the values in the test. See https://www.drupal.org/node/3129738',
+      // PHPUnit 9.
+      "The \"PHPUnit\TextUI\DefaultResultPrinter\" class is considered internal This class is not covered by the backward compatibility promise for PHPUnit. It may change without further notice. You should not use it from \"Drupal\Tests\Listeners\HtmlOutputPrinter\".",
+      'assertFileNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileDoesNotExist() instead.',
+      'assertRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertMatchesRegularExpression() instead.',
+      'assertNotRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDoesNotMatchRegularExpression() instead.',
+      'assertDirectoryNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryDoesNotExist() instead.',
+      'Support for using expectException() with PHPUnit\\Framework\\Error\\Warning is deprecated and will be removed in PHPUnit 10. Use expectWarning() instead.',
+      'Support for using expectException() with PHPUnit\\Framework\\Error\\Error is deprecated and will be removed in PHPUnit 10. Use expectError() instead.',
+      'assertDirectoryNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryIsNotWritable() instead.',
+      'assertFileNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileIsNotWritable() instead.',
+      'The at() matcher has been deprecated. It will be removed in PHPUnit 10. Please refactor your test to not rely on the order in which methods are invoked.',
     ];
   }
 
diff --git a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php
index a3f7916e9867..a85c32049972 100644
--- a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php
+++ b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php
@@ -2,15 +2,27 @@
 
 namespace Drupal\Tests\Listeners;
 
+use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
 use PHPUnit\Framework\TestResult;
-use PHPUnit\TextUI\ResultPrinter;
+
+// In order to manage different implementations across PHPUnit versions, we
+// dynamically load the base ResultPrinter class dependent on the PHPUnit runner
+// version.
+if (!class_exists(ResultPrinterBase::class, FALSE)) {
+  if (RunnerVersion::getMajor() < 9) {
+    class_alias('PHPUnit\TextUI\ResultPrinter', ResultPrinterBase::class);
+  }
+  else {
+    class_alias('PHPUnit\TextUI\DefaultResultPrinter', ResultPrinterBase::class);
+  }
+}
 
 /**
  * Defines a class for providing html output results for functional tests.
  *
  * @internal
  */
-class HtmlOutputPrinter extends ResultPrinter {
+class HtmlOutputPrinter extends ResultPrinterBase {
 
   use HtmlOutputPrinterTrait;
 
diff --git a/core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php b/core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php
new file mode 100644
index 000000000000..dc6aed489bfa
--- /dev/null
+++ b/core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Drupal\Tests;
+
+use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
+
+// In order to manage different method signatures between PHPUnit versions, we
+// dynamically load a compatibility trait dependent on the PHPUnit runner
+// version.
+if (!trait_exists(PhpunitVersionDependentTestCompatibilityTrait::class, FALSE)) {
+  class_alias("Drupal\TestTools\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\TestCompatibilityTrait", PhpUnitVersionDependentTestCompatibilityTrait::class);
+}
+
+/**
+ * Makes Drupal's test API forward compatible with multiple versions of PHPUnit.
+ */
+trait PhpUnitCompatibilityTrait {
+
+  use PhpUnitVersionDependentTestCompatibilityTrait;
+
+}
diff --git a/core/tests/Drupal/Tests/PhpUnitWarningsTest.php b/core/tests/Drupal/Tests/PhpUnitWarningsTest.php
index 6a741265e343..45d298ca36f0 100644
--- a/core/tests/Drupal/Tests/PhpUnitWarningsTest.php
+++ b/core/tests/Drupal/Tests/PhpUnitWarningsTest.php
@@ -2,12 +2,17 @@
 
 namespace Drupal\Tests;
 
+use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
+use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
+
 /**
  * @coversDefaultClass \Drupal\Tests\Traits\PhpUnitWarnings
  * @group legacy
  */
 class PhpUnitWarningsTest extends UnitTestCase {
 
+  use ExpectDeprecationTrait;
+
   /**
    * @expectedDeprecation Test warning for \Drupal\Tests\PhpUnitWarningsTest::testAddWarning()
    */
@@ -16,46 +21,66 @@ public function testAddWarning() {
   }
 
   /**
-   * @expectedDeprecation Using assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringContainsString() or assertStringContainsStringIgnoringCase() instead.
-   * @expectedDeprecation The optional $ignoreCase parameter of assertContains() is deprecated and will be removed in PHPUnit 9.
+   * Tests assertContains.
    */
   public function testAssertContains() {
+    if (RunnerVersion::getMajor() > 8) {
+      $this->markTestSkipped("In PHPUnit 9+, argument 2 passed to PHPUnit\Framework\Assert::assertContains() must be iterable.");
+    }
+    $this->expectDeprecation('Using assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringContainsString() or assertStringContainsStringIgnoringCase() instead.');
+    $this->expectDeprecation('The optional $ignoreCase parameter of assertContains() is deprecated and will be removed in PHPUnit 9.');
     $this->assertContains('string', 'aaaa_string_aaa');
     $this->assertContains('STRING', 'aaaa_string_aaa', '', TRUE);
   }
 
   /**
-   * @expectedDeprecation Using assertNotContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringNotContainsString() or assertStringNotContainsStringIgnoringCase() instead.
-   * @expectedDeprecation The optional $ignoreCase parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9.
+   * Tests assertNotContains.
    */
   public function testAssertNotContains() {
+    if (RunnerVersion::getMajor() > 8) {
+      $this->markTestSkipped("In PHPUnit 9+, argument 2 passed to PHPUnit\Framework\Assert::assertNotContains() must be iterable.");
+    }
+    $this->expectDeprecation('Using assertNotContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringNotContainsString() or assertStringNotContainsStringIgnoringCase() instead.');
+    $this->expectDeprecation('The optional $ignoreCase parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9.');
     $this->assertNotContains('foo', 'bar');
     $this->assertNotContains('FOO', 'bar', '', TRUE);
   }
 
   /**
-   * @expectedDeprecation assertArraySubset() is deprecated and will be removed in PHPUnit 9.
+   * Tests assertArraySubset.
    */
   public function testAssertArraySubset() {
+    if (RunnerVersion::getMajor() > 8) {
+      $this->markTestSkipped("In PHPUnit 9+, assertArraySubset() is removed.");
+    }
+    $this->expectDeprecation('assertArraySubset() is deprecated and will be removed in PHPUnit 9.');
     $this->assertArraySubset(['a'], ['a', 'b']);
   }
 
   /**
-   * @expectedDeprecation 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.
+   * Tests assertInternalType.
    */
   public function testAssertInternalType() {
+    if (RunnerVersion::getMajor() > 8) {
+      $this->markTestSkipped("In PHPUnit 9+, assertInternalType() is removed.");
+    }
+    $this->expectDeprecation('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.');
     $this->assertInternalType('string', 'string');
   }
 
   /**
-   * @expectedDeprecation assertAttributeEquals() is deprecated and will be removed in PHPUnit 9.
-   * @expectedDeprecation readAttribute() is deprecated and will be removed in PHPUnit 9.
-   * @expectedDeprecation getObjectAttribute() is deprecated and will be removed in PHPUnit 9.
-   * @expectedDeprecation assertAttributeSame() is deprecated and will be removed in PHPUnit 9.
-   * @expectedDeprecation assertAttributeInstanceOf() is deprecated and will be removed in PHPUnit 9.
-   * @expectedDeprecation assertAttributeEmpty() is deprecated and will be removed in PHPUnit 9.
+   * Tests assertion methods accessing class attributes.
    */
   public function testAssertAttribute() {
+    if (RunnerVersion::getMajor() > 8) {
+      $this->markTestSkipped("In PHPUnit 9+, assertion methods accessing class attributes are removed.");
+    }
+    $this->expectDeprecation('assertAttributeEquals() is deprecated and will be removed in PHPUnit 9.');
+    $this->expectDeprecation('readAttribute() is deprecated and will be removed in PHPUnit 9.');
+    $this->expectDeprecation('getObjectAttribute() is deprecated and will be removed in PHPUnit 9.');
+    $this->expectDeprecation('assertAttributeSame() is deprecated and will be removed in PHPUnit 9.');
+    $this->expectDeprecation('assertAttributeInstanceOf() is deprecated and will be removed in PHPUnit 9.');
+    $this->expectDeprecation('assertAttributeEmpty() is deprecated and will be removed in PHPUnit 9.');
     $obj = new class() {
       protected $attribute = 'value';
       protected $class;
@@ -73,16 +98,24 @@ public function __construct() {
   }
 
   /**
-   * @expectedDeprecation The optional $canonicalize parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsCanonicalizing() instead.
+   * Tests assertEquals.
    */
   public function testAssertEquals() {
+    if (RunnerVersion::getMajor() > 8) {
+      $this->markTestSkipped("In PHPUnit 9+, the \$canonicalize parameter of assertEquals() is removed.");
+    }
+    $this->expectDeprecation('The optional $canonicalize parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsCanonicalizing() instead.');
     $this->assertEquals(['a', 'b'], ['b', 'a'], '', 0.0, 10, TRUE);
   }
 
   /**
-   * @expectedDeprecation expectExceptionMessageRegExp() is deprecated in PHPUnit 8 and will be removed in PHPUnit 9.
+   * Tests expectExceptionMessageRegExp.
    */
   public function testExpectExceptionMessageRegExp() {
+    if (RunnerVersion::getMajor() > 8) {
+      $this->markTestSkipped("In PHPUnit 9+, expectExceptionMessageRegExp() is removed.");
+    }
+    $this->expectDeprecation('expectExceptionMessageRegExp() is deprecated in PHPUnit 8 and will be removed in PHPUnit 9.');
     $this->expectException(\Exception::class);
     $this->expectExceptionMessageRegExp('/An exception .*/');
     throw new \Exception('An exception has been triggered');
diff --git a/core/tests/Drupal/Tests/Traits/PhpUnitWarnings.php b/core/tests/Drupal/Tests/Traits/PhpUnitWarnings.php
index d2e3039d208e..9e16ae952796 100644
--- a/core/tests/Drupal/Tests/Traits/PhpUnitWarnings.php
+++ b/core/tests/Drupal/Tests/Traits/PhpUnitWarnings.php
@@ -37,6 +37,16 @@ trait PhpUnitWarnings {
     'expectExceptionMessageRegExp() is deprecated in PHPUnit 8 and will be removed in PHPUnit 9.',
     // Warning for testing.
     'Test warning for \Drupal\Tests\PhpUnitWarningsTest::testAddWarning()',
+    // PHPUnit 9.
+    'assertFileNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileDoesNotExist() instead.',
+    'assertRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertMatchesRegularExpression() instead.',
+    'assertNotRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDoesNotMatchRegularExpression() instead.',
+    'assertDirectoryNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryDoesNotExist() instead.',
+    'Support for using expectException() with PHPUnit\\Framework\\Error\\Warning is deprecated and will be removed in PHPUnit 10. Use expectWarning() instead.',
+    'Support for using expectException() with PHPUnit\\Framework\\Error\\Error is deprecated and will be removed in PHPUnit 10. Use expectError() instead.',
+    'assertDirectoryNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryIsNotWritable() instead.',
+    'assertFileNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileIsNotWritable() instead.',
+    'The at() matcher has been deprecated. It will be removed in PHPUnit 10. Please refactor your test to not rely on the order in which methods are invoked.',
   ];
 
   /**
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index 3a4e035ce060..20dcb1d07a32 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -20,6 +20,7 @@
 abstract class UnitTestCase extends TestCase {
 
   use PhpUnitWarnings;
+  use PhpUnitCompatibilityTrait;
 
   /**
    * The random generator.
-- 
GitLab