diff --git a/features.module b/features.module
index 07e2740..204617f 100644
--- a/features.module
+++ b/features.module
@@ -5,53 +5,30 @@
  * Main hooks for Features module.
  */
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\features\Hook\FeaturesHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function features_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.features':
-      $output = '';
-      $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The Features module provides a user interface for exporting bundles of configuration into modules. For more information, see the online documentation for <a href=":url">Features module</a>', [
-        ':url' => 'http://drupal.org/node/2404427',
-      ]) . '</p>';
-      return $output;
-  }
+  return \Drupal::service(FeaturesHooks::class)->help($route_name, $route_match);
 }
 
 /**
  * Implements hook_file_download().
  */
+#[LegacyHook]
 function features_file_download($uri) {
-  $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
-  $scheme = $stream_wrapper_manager->getScheme($uri);
-  $target = $stream_wrapper_manager->getTarget($uri);
-
-  if ($scheme == 'temporary' && $target) {
-    $request = \Drupal::request();
-    $route = $request->attributes->get('_route');
-    // Check if we were called by Features download route.
-    // No additional access checking needed here: route requires
-    // "export configuration" permission, token is validated by the controller.
-    // @see \Drupal\features\Controller\FeaturesController::downloadExport()
-    if ($route == 'features.export_download') {
-      return [
-        'Content-disposition' => 'attachment; filename="' . $target . '"',
-      ];
-    }
-  }
+  return \Drupal::service(FeaturesHooks::class)->fileDownload($uri);
 }
 
 /**
  * Implements hook_modules_installed().
  */
+#[LegacyHook]
 function features_modules_installed($modules) {
-  if (!in_array('features', $modules)) {
-    /** @var \Drupal\features\FeaturesAssignerInterface $assigner */
-    $assigner = \Drupal::service('features_assigner');
-    $assigner->purgeConfiguration();
-  }
+  \Drupal::service(FeaturesHooks::class)->modulesInstalled($modules);
 }
diff --git a/features.services.yml b/features.services.yml
index 2b9e1e2..6582ac7 100644
--- a/features.services.yml
+++ b/features.services.yml
@@ -49,3 +49,7 @@ services:
   logger.channel.features:
     parent: logger.channel_base
     arguments: ['features']
+
+  Drupal\features\Hook\FeaturesHooks:
+    class: Drupal\features\Hook\FeaturesHooks
+    autowire: true
diff --git a/modules/features_ui/features_ui.module b/modules/features_ui/features_ui.module
index cd2c165..1c3660a 100644
--- a/modules/features_ui/features_ui.module
+++ b/modules/features_ui/features_ui.module
@@ -5,43 +5,22 @@
  * Allows site administrators to modify configuration.
  */
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\features_ui\Hook\FeaturesUiHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function features_ui_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'features.assignment':
-      $output = '';
-      $output .= '<p>' . t('Bundles are used to collect together groups of features. A bundle provides a shared <a href=":namespace">namespace</a> for all features included in it, which prevents conflicts and helps distinguish your features from those produced for other purposes. Common uses of bundles include:', [':namespace' => 'http://en.wikipedia.org/wiki/Namespace']);
-      $output .= '<ul>';
-      $output .= '<li>' . t('Custom features for use on a particular site.') . '</li>';
-      $output .= '<li>' . t('The features of a given <a href=":distributions">distribution</a>.', [':distributions' => 'https://www.drupal.org/documentation/build/distributions']) . '</li>';
-      $output .= '</ul></p>';
-      $output .= '<p>' . t("Use the form below to manage bundles. Each bundle comes with a set of assignment methods. By configuring and ordering the assignment methods, you can set the defaults for what does and doesn't get packaged into features for your bundle. Use the <em>Bundle</em> select to choose which bundle to edit, or chose <em>--New--</em> to create a new bundle. The <em>Default</em> bundle does not include a namespace and cannot be deleted.") . '</p>';
-      return $output;
-
-    case 'features.export':
-      $output = '';
-      $output .= '<p>' . t('Export packages of configuration into modules.') . '</p>';
-      return $output;
-  }
+  return \Drupal::service(FeaturesUiHooks::class)->help($route_name, $route_match);
 }
 
 /**
  * Implements hook_theme().
  */
+#[LegacyHook]
 function features_ui_theme() {
-  return [
-    'features_assignment_configure_form' => [
-      'render element' => 'form',
-      'file' => 'features_ui.admin.inc',
-    ],
-    'features_items' => [
-      'variables' => [
-        'items' => [],
-      ],
-    ],
-  ];
+  return \Drupal::service(FeaturesUiHooks::class)->theme();
 }
diff --git a/modules/features_ui/features_ui.services.yml b/modules/features_ui/features_ui.services.yml
new file mode 100644
index 0000000..a13bbe0
--- /dev/null
+++ b/modules/features_ui/features_ui.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\features_ui\Hook\FeaturesUiHooks:
+    class: Drupal\features_ui\Hook\FeaturesUiHooks
+    autowire: true
diff --git a/modules/features_ui/src/Form/FeaturesEditForm.php b/modules/features_ui/src/Form/FeaturesEditForm.php
index 941cb22..ec7e160 100644
--- a/modules/features_ui/src/Form/FeaturesEditForm.php
+++ b/modules/features_ui/src/Form/FeaturesEditForm.php
@@ -2,18 +2,16 @@
 
 namespace Drupal\features_ui\Form;
 
+use Drupal\Component\Utility\DeprecationHelper;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\SortArray;
 use Drupal\Component\Utility\Xss;
-use Drupal\features\FeaturesAssignerInterface;
-use Drupal\features\FeaturesGeneratorInterface;
 use Drupal\features\FeaturesManagerInterface;
 use Drupal\features\ConfigurationItem;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Component\Render\FormattableMarkup;
-use Drupal\config_update\ConfigRevertInterface;
 
 /**
  * Defines the features settings form.
@@ -433,7 +431,18 @@ class FeaturesEditForm extends FormBase {
     ];
 
     // Filter field used in JavaScript, so JavaScript will unhide it.
-    $element['features_filter_wrapper'] = [
+    $element['features_filter_wrapper'] = DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.2.0', fn() => [
+      '#type' => 'fieldset',
+      '#title' => $this->t('Filters'),
+      '#title_display' => 'invisible',
+      '#tree' => FALSE,
+      '#prefix' => '<div id="features-filter" class="features-filter js-features-filter visually-hidden">',
+      '#suffix' => '</div>',
+      '#weight' => -10,
+      '#attributes' => [
+        'class' => ['features-filter__fieldset', 'container-inline'],
+      ],
+    ], fn() => [
       '#type' => 'fieldgroup',
       '#title' => $this->t('Filters'),
       '#title_display' => 'invisible',
@@ -444,7 +453,7 @@ class FeaturesEditForm extends FormBase {
       '#attributes' => [
         'class' => ['features-filter__fieldset', 'container-inline'],
       ],
-    ];
+    ]);
     $element['features_filter_wrapper']['features_filter'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Search'),
@@ -580,7 +589,7 @@ class FeaturesEditForm extends FormBase {
         foreach ($sections as $section) {
           $element[$component][$section] = [
             '#type' => 'checkboxes',
-            '#options' => !empty($component_info['_features_options'][$section]) ?  $this->domDecodeOptions($component_info['_features_options'][$section]) : [],
+            '#options' => !empty($component_info['_features_options'][$section]) ? $this->domDecodeOptions($component_info['_features_options'][$section]) : [],
             '#default_value' => !empty($component_info['_features_selected'][$section]) ? $this->domDecodeOptions($component_info['_features_selected'][$section], FALSE) : [],
             '#attributes' => [
               'class' => ['component-' . $section, 'js-component-' . $section],
@@ -692,7 +701,7 @@ class FeaturesEditForm extends FormBase {
       if (isset($config[$item_name])) {
         $item = $config[$item_name];
         // Remove any conflicts if those are not being allowed.
-        // if ($this->allowConflicts || !isset($this->conflicts[$item['type']][$item['name_short']])) {
+        // if ($this->allowConflicts || !isset($this->conflicts[$item['type']][$item['name_short']])) {.
         $exported_features_info[$item->getType()][$item->getShortName()] = $item->getLabel();
         // }
       }
@@ -1037,7 +1046,8 @@ class FeaturesEditForm extends FormBase {
         try {
           $this->configRevert->import($type, $item['name_short']);
           $this->messenger()->addStatus($this->t('Imported @name', ['@name' => $config_name]));
-        } catch (\Exception $e) {
+        }
+        catch (\Exception $e) {
           $this->messenger()->addError($this->t('Error importing @name : @message',
             ['@name' => $config_name, '@message' => $e->getMessage()]));
         }
diff --git a/modules/features_ui/src/Hook/FeaturesUiHooks.php b/modules/features_ui/src/Hook/FeaturesUiHooks.php
new file mode 100644
index 0000000..fefa222
--- /dev/null
+++ b/modules/features_ui/src/Hook/FeaturesUiHooks.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\features_ui\Hook;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for features_ui.
+ */
+class FeaturesUiHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      case 'features.assignment':
+        $output = '';
+        $output .= '<p>' . $this->t('Bundles are used to collect together groups of features. A bundle provides a shared <a href=":namespace">namespace</a> for all features included in it, which prevents conflicts and helps distinguish your features from those produced for other purposes. Common uses of bundles include:', [
+          ':namespace' => 'http://en.wikipedia.org/wiki/Namespace',
+        ]);
+        $output .= '<ul>';
+        $output .= '<li>' . $this->t('Custom features for use on a particular site.') . '</li>';
+        $output .= '<li>' . $this->t('The features of a given <a href=":distributions">distribution</a>.', [
+          ':distributions' => 'https://www.drupal.org/documentation/build/distributions',
+        ]) . '</li>';
+        $output .= '</ul></p>';
+        $output .= '<p>' . $this->t("Use the form below to manage bundles. Each bundle comes with a set of assignment methods. By configuring and ordering the assignment methods, you can set the defaults for what does and doesn't get packaged into features for your bundle. Use the <em>Bundle</em> select to choose which bundle to edit, or chose <em>--New--</em> to create a new bundle. The <em>Default</em> bundle does not include a namespace and cannot be deleted.") . '</p>';
+        return $output;
+
+      case 'features.export':
+        $output = '';
+        $output .= '<p>' . $this->t('Export packages of configuration into modules.') . '</p>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_theme().
+   */
+  #[Hook('theme')]
+  public static function theme() {
+    return [
+      'features_assignment_configure_form' => [
+        'render element' => 'form',
+        'file' => 'features_ui.admin.inc',
+      ],
+      'features_items' => [
+        'variables' => [
+          'items' => [],
+        ],
+      ],
+    ];
+  }
+
+}
diff --git a/modules/features_ui/tests/src/Functional/FeaturesBundleUiTest.php b/modules/features_ui/tests/src/Functional/FeaturesBundleUiTest.php
index f90cd96..40df21c 100644
--- a/modules/features_ui/tests/src/Functional/FeaturesBundleUiTest.php
+++ b/modules/features_ui/tests/src/Functional/FeaturesBundleUiTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features_ui\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\features\FeaturesBundleInterface;
 use Drupal\Tests\BrowserTestBase;
@@ -12,6 +13,7 @@ use Drupal\Tests\BrowserTestBase;
  * @group features_ui
  */
 #[RunTestsInSeparateProcesses]
+#[Group('features_ui')]
 class FeaturesBundleUiTest extends BrowserTestBase {
 
   /**
diff --git a/modules/features_ui/tests/src/Functional/FeaturesCreateUiTest.php b/modules/features_ui/tests/src/Functional/FeaturesCreateUiTest.php
index bc1d30a..5bdc922 100644
--- a/modules/features_ui/tests/src/Functional/FeaturesCreateUiTest.php
+++ b/modules/features_ui/tests/src/Functional/FeaturesCreateUiTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features_ui\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\Component\Serialization\Yaml;
 use Drupal\Core\Archiver\ArchiveTar;
@@ -13,6 +14,7 @@ use Drupal\Tests\BrowserTestBase;
  * @group features_ui
  */
 #[RunTestsInSeparateProcesses]
+#[Group('features_ui')]
 class FeaturesCreateUiTest extends BrowserTestBase {
 
   /**
diff --git a/modules/features_ui/tests/src/FunctionalJavascript/FeaturesUiAjaxTest.php b/modules/features_ui/tests/src/FunctionalJavascript/FeaturesUiAjaxTest.php
index b474e77..3f46c9d 100644
--- a/modules/features_ui/tests/src/FunctionalJavascript/FeaturesUiAjaxTest.php
+++ b/modules/features_ui/tests/src/FunctionalJavascript/FeaturesUiAjaxTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\features_ui\FunctionalJavascript;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\Core\Url;
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 
@@ -10,6 +12,8 @@ use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
  *
  * @group features_ui
  */
+#[Group('features_ui')]
+#[RunTestsInSeparateProcesses]
 class FeaturesUiAjaxTest extends WebDriverTestBase {
 
   /**
diff --git a/src/Hook/FeaturesHooks.php b/src/Hook/FeaturesHooks.php
new file mode 100644
index 0000000..df9d77c
--- /dev/null
+++ b/src/Hook/FeaturesHooks.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace Drupal\features\Hook;
+
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for features.
+ */
+class FeaturesHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      case 'help.page.features':
+        $output = '';
+        $output .= '<h3>' . $this->t('About') . '</h3>';
+        $output .= '<p>' . $this->t('The Features module provides a user interface for exporting bundles of configuration into modules. For more information, see the online documentation for <a href=":url">Features module</a>', [
+          ':url' => 'http://drupal.org/node/2404427',
+        ]) . '</p>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_file_download().
+   */
+  #[Hook('file_download')]
+  public static function fileDownload($uri) {
+    $stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
+    $scheme = $stream_wrapper_manager->getScheme($uri);
+    $target = $stream_wrapper_manager->getTarget($uri);
+    if ($scheme == 'temporary' && $target) {
+      $request = \Drupal::request();
+      $route = $request->attributes->get('_route');
+      // Check if we were called by Features download route.
+      // No additional access checking needed here: route requires
+      // "export configuration" permission, token is validated by the controller.
+      // @see \Drupal\features\Controller\FeaturesController::downloadExport()
+      if ($route == 'features.export_download') {
+        return [
+          'Content-disposition' => 'attachment; filename="' . $target . '"',
+        ];
+      }
+    }
+  }
+
+  /**
+   * Implements hook_modules_installed().
+   */
+  #[Hook('modules_installed')]
+  public static function modulesInstalled($modules) {
+    if (!in_array('features', $modules)) {
+      /** @var \Drupal\features\FeaturesAssignerInterface $assigner */
+      $assigner = \Drupal::service('features_assigner');
+      $assigner->purgeConfiguration();
+    }
+  }
+
+}
diff --git a/tests/src/Kernel/Entity/FeaturesBundleIntegrationTest.php b/tests/src/Kernel/Entity/FeaturesBundleIntegrationTest.php
index cfdefdb..42e0aa8 100644
--- a/tests/src/Kernel/Entity/FeaturesBundleIntegrationTest.php
+++ b/tests/src/Kernel/Entity/FeaturesBundleIntegrationTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features\Kernel\Entity;
 
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\features\Entity\FeaturesBundle;
 use Drupal\features\FeaturesBundleInterface;
@@ -12,6 +13,7 @@ use Drupal\KernelTests\KernelTestBase;
  * @group features
  */
 #[RunTestsInSeparateProcesses]
+#[Group('features')]
 class FeaturesBundleIntegrationTest extends KernelTestBase {
 
   /**
diff --git a/tests/src/Kernel/FeaturesAssignTest.php b/tests/src/Kernel/FeaturesAssignTest.php
index d012835..f5915f3 100644
--- a/tests/src/Kernel/FeaturesAssignTest.php
+++ b/tests/src/Kernel/FeaturesAssignTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features\Kernel;
 
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\features\ConfigurationItem;
@@ -14,6 +15,7 @@ use Drupal\Core\Config\InstallStorage;
  * @group features
  */
 #[RunTestsInSeparateProcesses]
+#[Group('features')]
 class FeaturesAssignTest extends KernelTestBase {
 
   const PACKAGE_NAME = 'my_test_package';
diff --git a/tests/src/Kernel/FeaturesAssignerTest.php b/tests/src/Kernel/FeaturesAssignerTest.php
index d6a0f8c..d2f7733 100644
--- a/tests/src/Kernel/FeaturesAssignerTest.php
+++ b/tests/src/Kernel/FeaturesAssignerTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features\Kernel;
 
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\KernelTests\KernelTestBase;
 
@@ -11,6 +12,7 @@ use Drupal\KernelTests\KernelTestBase;
  * @group features
  */
 #[RunTestsInSeparateProcesses]
+#[Group('features')]
 class FeaturesAssignerTest extends KernelTestBase {
   /**
    * {@inheritdoc}
diff --git a/tests/src/Kernel/FeaturesGenerateTest.php b/tests/src/Kernel/FeaturesGenerateTest.php
index 5e4b5a5..34cc41a 100644
--- a/tests/src/Kernel/FeaturesGenerateTest.php
+++ b/tests/src/Kernel/FeaturesGenerateTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features\Kernel;
 
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\Component\Serialization\Yaml;
 use Drupal\Core\Archiver\ArchiveTar;
@@ -14,6 +15,7 @@ use org\bovigo\vfs\vfsStream;
  * @group features
  */
 #[RunTestsInSeparateProcesses]
+#[Group('features')]
 class FeaturesGenerateTest extends KernelTestBase {
 
   const PACKAGE_NAME = 'my_test_package';
diff --git a/tests/src/Kernel/FeaturesManagerKernelTest.php b/tests/src/Kernel/FeaturesManagerKernelTest.php
index 9cfdc15..3c98f52 100644
--- a/tests/src/Kernel/FeaturesManagerKernelTest.php
+++ b/tests/src/Kernel/FeaturesManagerKernelTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features\Kernel;
 
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\features\ConfigurationItem;
@@ -13,6 +14,7 @@ use Drupal\features\Package;
  * @group features
  */
 #[RunTestsInSeparateProcesses]
+#[Group('features')]
 class FeaturesManagerKernelTest extends KernelTestBase {
   /**
    * {@inheritdoc}
diff --git a/tests/src/Unit/ConfigurationItemTest.php b/tests/src/Unit/ConfigurationItemTest.php
index 6eb2748..e7445fb 100644
--- a/tests/src/Unit/ConfigurationItemTest.php
+++ b/tests/src/Unit/ConfigurationItemTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features\Unit;
 
+use PHPUnit\Framework\Attributes\Group;
 use Drupal\features\ConfigurationItem;
 use Drupal\features\FeaturesManagerInterface;
 use PHPUnit\Framework\TestCase;
@@ -10,6 +11,7 @@ use PHPUnit\Framework\TestCase;
  * @coversDefaultClass \Drupal\features\ConfigurationItem
  * @group features
  */
+#[Group('features')]
 class ConfigurationItemTest extends TestCase {
 
   /**
diff --git a/tests/src/Unit/FeaturesBundleTest.php b/tests/src/Unit/FeaturesBundleTest.php
index 1478e2b..8fbb13d 100644
--- a/tests/src/Unit/FeaturesBundleTest.php
+++ b/tests/src/Unit/FeaturesBundleTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\features\Unit;
 
+use PHPUnit\Framework\Attributes\Group;
 use Drupal\features\Entity\FeaturesBundle;
 use Drupal\Tests\UnitTestCase;
 use Prophecy\PhpUnit\ProphecyTrait;
@@ -10,6 +11,7 @@ use Prophecy\PhpUnit\ProphecyTrait;
  * @coversDefaultClass Drupal\features\Entity\FeaturesBundle
  * @group features
  */
+#[Group('features')]
 class FeaturesBundleTest extends UnitTestCase {
 
   use ProphecyTrait;
diff --git a/tests/src/Unit/FeaturesManagerTest.php b/tests/src/Unit/FeaturesManagerTest.php
index c2d1ba0..94fe7dd 100644
--- a/tests/src/Unit/FeaturesManagerTest.php
+++ b/tests/src/Unit/FeaturesManagerTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\features\Unit;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\DataProvider;
 use Drupal\Component\Serialization\Yaml;
 use Drupal\config_update\ConfigDiffInterface;
 use Drupal\config_update\ConfigRevertInterface;
@@ -31,6 +33,7 @@ use Prophecy\PhpUnit\ProphecyTrait;
  * @coversDefaultClass Drupal\features\FeaturesManager
  * @group features
  */
+#[Group('features')]
 class FeaturesManagerTest extends UnitTestCase {
   /**
    * The name of the install profile.
@@ -172,6 +175,9 @@ class FeaturesManagerTest extends UnitTestCase {
     $this->featuresManager = new FeaturesManager($this->root, $this->entityTypeManager, $this->configFactory, $this->configStorage, $this->configManager, $this->moduleHandler, $this->configReverter, $this->moduleExtensionList, $this->extensionPathResolver);
   }
 
+  /**
+   *
+   */
   protected function setupVfsWithTestFeature() {
     vfsStream::setup('drupal');
     \Drupal::getContainer()->setParameter('app.root', 'vfs://drupal');
@@ -215,6 +221,7 @@ EOT
    * @covers ::getFullName
    * @dataProvider providerTestGetFullName
    */
+  #[DataProvider('providerTestGetFullName')]
   public function testGetFullName($type, $name, $expected) {
     $this->assertEquals($this->featuresManager->getFullName($type, $name), $expected);
   }
@@ -811,6 +818,7 @@ EOT
    *
    * @dataProvider providerTestMergeInfoArray
    */
+  #[DataProvider('providerTestMergeInfoArray')]
   public function testMergeInfoArray($expected, $info1, $info2, $keys = []) {
     $this->assertSame($expected, $this->featuresManager->mergeInfoArray($info1, $info2, $keys));
   }
diff --git a/tests/src/Unit/PackageTest.php b/tests/src/Unit/PackageTest.php
index 8cf82dc..865c0a3 100644
--- a/tests/src/Unit/PackageTest.php
+++ b/tests/src/Unit/PackageTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\features\Unit;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\Depends;
 use Drupal\features\Package;
 use PHPUnit\Framework\TestCase;
 
@@ -9,6 +11,7 @@ use PHPUnit\Framework\TestCase;
  * @coversDefaultClass \Drupal\features\Package
  * @group features
  */
+#[Group('features')]
 class PackageTest extends TestCase {
 
   /**
@@ -25,7 +28,7 @@ class PackageTest extends TestCase {
       'test_feature',
     ]);
     // Test that duplicates are removed, results sorted, and the package cannot
-    /// require itself.
+    // require itself.
     $expected = [
       'my_module',
       'some_module',
@@ -50,7 +53,7 @@ class PackageTest extends TestCase {
       $package->appendDependency($dependency);
     }
     // Test that duplicates are removed, results sorted, and the package cannot
-    /// require itself.
+    // require itself.
     $expected = [
       'my_module',
       'some_module',
@@ -85,6 +88,7 @@ class PackageTest extends TestCase {
    * @depends testGetConfig
    * @covers ::appendConfig
    */
+  #[Depends('testGetConfig')]
   public function testAppendConfig(Package $package) {
     $package->appendConfig('test_config_a');
     $package->appendConfig('test_config_c');
@@ -99,6 +103,7 @@ class PackageTest extends TestCase {
    * @depends testAppendConfig
    * @covers ::removeConfig
    */
+  #[Depends('testAppendConfig')]
   public function testRemoveConfig(Package $package) {
     $package->removeConfig('test_config_a');
 
