diff --git a/Components/AuthorityTest.php b/Components/AuthorityTest.php
index 8a17d62b..c59a8d0f 100644
--- a/Components/AuthorityTest.php
+++ b/Components/AuthorityTest.php
@@ -16,20 +16,19 @@
 use League\Uri\Http;
 use League\Uri\Uri;
 use League\Uri\UriString;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 
 use function parse_url;
 
-/**
- * @group userinfo
- * @coversDefaultClass \League\Uri\Components\Authority
- */
+#[CoversClass(Authority::class)]
+#[Group('userinfo')]
 final class AuthorityTest extends TestCase
 {
-    /**
-     * @dataProvider validAuthorityDataProvider
-     */
+    #[DataProvider('validAuthorityDataProvider')]
     public function testConstructor(
         ?string $authority,
         ?string $host,
@@ -90,9 +89,7 @@ public static function validAuthorityDataProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider invalidAuthorityDataProvider
-     */
+    #[DataProvider('invalidAuthorityDataProvider')]
     public function testConstructorFails(string $authority): void
     {
         $this->expectException(SyntaxError::class);
@@ -116,9 +113,7 @@ public function testWithHost(): void
         self::assertNotEquals($authority, $authority->withHost('[::1]'));
     }
 
-    /**
-     * @dataProvider invalidHostDataProvider
-     */
+    #[DataProvider('invalidHostDataProvider')]
     public function testWithHostFails(?string $host): void
     {
         $this->expectException(SyntaxError::class);
@@ -164,9 +159,7 @@ public function testWithUserInfoFails(): void
         Authority::new('foo:bar@example.com:443')->withUserInfo("\0foo", 'bar');
     }
 
-    /**
-     * @dataProvider stringRepresentationDataProvider
-    */
+    #[DataProvider('stringRepresentationDataProvider')]
     public function testAuthorityStringRepresentation(
         ?string $authority,
         string $string,
@@ -220,9 +213,7 @@ public static function stringRepresentationDataProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(UriInterface|Psr7UriInterface $uri, ?string $expected, array $components): void
     {
         $authority = Authority::fromUri($uri);
diff --git a/Components/DataPathTest.php b/Components/DataPathTest.php
index ed7de3f8..584dede8 100644
--- a/Components/DataPathTest.php
+++ b/Components/DataPathTest.php
@@ -15,6 +15,9 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 
@@ -22,11 +25,9 @@
 use function dirname;
 use function file_get_contents;
 
-/**
- * @group path
- * @group datapath
- * @coversDefaultClass \League\Uri\Components\DataPath
- */
+#[CoversClass(DataPath::class)]
+#[Group('path')]
+#[Group('datapath')]
 final class DataPathTest extends TestCase
 {
     private string $rootPath;
@@ -71,9 +72,7 @@ public function testConstructorFailedMalformePath(): void
         DataPath::new('€');
     }
 
-    /**
-     * @dataProvider invalidDataUriPath
-     */
+    #[DataProvider('invalidDataUriPath')]
     public function testCreateFromPathFailed(string $path): void
     {
         $this->expectException(SyntaxError::class);
@@ -81,9 +80,7 @@ public function testCreateFromPathFailed(string $path): void
         DataPath::fromFileContents($path);
     }
 
-    /**
-     * @dataProvider invalidDataUriPath
-     */
+    #[DataProvider('invalidDataUriPath')]
     public function testConstructorFailed(string $path): void
     {
         $this->expectException(SyntaxError::class);
@@ -98,9 +95,7 @@ public static function invalidDataUriPath(): array
         ];
     }
 
-    /**
-     * @dataProvider validPathContent
-     */
+    #[DataProvider('validPathContent')]
     public function testDefaultConstructor(string $path, string $expected): void
     {
         self::assertSame($expected, DataPath::new($path)->toString());
@@ -124,9 +119,7 @@ public static function validPathContent(): array
         ];
     }
 
-    /**
-     * @dataProvider validFilePath
-     */
+    #[DataProvider('validFilePath')]
     public function testCreateFromPath(string $path, string $mimetype, string $mediatype): void
     {
         $uri = DataPath::fromFileContents($path);
@@ -162,9 +155,7 @@ public function testWithParametersOnBinaryData(): void
         self::assertSame($expected, $newUri->getParameters());
     }
 
-    /**
-     * @dataProvider invalidParametersString
-     */
+    #[DataProvider('invalidParametersString')]
     public function testWithParametersFailedWithInvalidParameters(string $path, string $parameters): void
     {
         $this->expectException(SyntaxError::class);
@@ -186,17 +177,13 @@ public static function invalidParametersString(): array
         ];
     }
 
-    /**
-     * @dataProvider fileProvider
-     */
+    #[DataProvider('fileProvider')]
     public function testToBinary(DataPath $uri): void
     {
         self::assertTrue($uri->toBinary()->isBinaryData());
     }
 
-    /**
-     * @dataProvider fileProvider
-     */
+    #[DataProvider('fileProvider')]
     public function testToAscii(DataPath $uri): void
     {
         self::assertFalse($uri->toAscii()->isBinaryData());
@@ -212,9 +199,7 @@ public static function fileProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider invalidParameters
-     */
+    #[DataProvider('invalidParameters')]
     public function testUpdateParametersFailed(string $parameters): void
     {
         $this->expectException(SyntaxError::class);
@@ -299,9 +284,7 @@ public function testInvalidMimetype(): void
     }
 
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(Psr7UriInterface|UriInterface $uri, ?string $expected): void
     {
         $path = DataPath::fromUri($uri);
diff --git a/Components/DomainTest.php b/Components/DomainTest.php
index 0396d4b1..5dab01aa 100644
--- a/Components/DomainTest.php
+++ b/Components/DomainTest.php
@@ -18,13 +18,14 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 
-/**
- * @group host
- * @coversDefaultClass \League\Uri\Components\Domain
- */
+#[CoversClass(Domain::class)]
+#[Group('host')]
 final class DomainTest extends TestCase
 {
     public function testItCanBeInstantiatedWithAHostInterfaceImplementingObject(): void
@@ -60,8 +61,8 @@ public function testIterator(): void
 
     /**
      * Test valid Domain.
-     * @dataProvider validDomainProvider
      */
+    #[DataProvider('validDomainProvider')]
     public function testValidDomain(string $host, string $uri, string $iri): void
     {
         $host = Domain::new($host);
@@ -111,9 +112,7 @@ public static function validDomainProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider invalidDomainProvider
-     */
+    #[DataProvider('invalidDomainProvider')]
     public function testInvalidDomain(?string $invalid): void
     {
         $this->expectException(SyntaxError::class);
@@ -150,9 +149,7 @@ public static function invalidDomainProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider isAbsoluteProvider
-     */
+    #[DataProvider('isAbsoluteProvider')]
     public function testIsAbsolute(string $raw, bool $expected): void
     {
         self::assertSame($expected, Domain::new($raw)->isAbsolute());
@@ -174,9 +171,7 @@ public function testIpProperty(): void
         self::assertNull($host->getIp());
     }
 
-    /**
-     * @dataProvider hostnamesProvider
-     */
+    #[DataProvider('hostnamesProvider')]
     public function testValidUnicodeDomain(string $unicode, string $ascii): void
     {
         $host = Domain::new($unicode);
@@ -211,9 +206,7 @@ public static function hostnamesProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider countableProvider
-     */
+    #[DataProvider('countableProvider')]
     public function testCountable(string $host, int $nblabels): void
     {
         self::assertCount($nblabels, Domain::new($host));
@@ -227,9 +220,7 @@ public static function countableProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider createFromLabelsValid
-     */
+    #[DataProvider('createFromLabelsValid')]
     public function testCreateFromLabels(iterable $input, string $expected): void
     {
         self::assertSame($expected, (string) Domain::fromLabels(...$input));
@@ -279,9 +270,7 @@ public function testLabels(): void
         self::assertSame(['', 'localhost'], [...Domain::new('localhost.')]);
     }
 
-    /**
-     * @dataProvider withoutProvider
-     */
+    #[DataProvider('withoutProvider')]
     public function testWithout(string $host, int $without, string $res): void
     {
         self::assertSame($res, (string) Domain::new($host)->withoutLabel($without));
@@ -309,9 +298,7 @@ public function testWithoutTriggersException(): void
         Domain::new('bébé.be')->withoutLabel(-23);
     }
 
-    /**
-     * @dataProvider validPrepend
-     */
+    #[DataProvider('validPrepend')]
     public function testPrepend(string $raw, string $prepend, string $expected): void
     {
         self::assertSame($expected, (string) Domain::new($raw)->prepend($prepend));
@@ -343,9 +330,7 @@ public function testPrependNull(): void
         self::assertSame($domain->prepend(null), $domain);
     }
 
-    /**
-     * @dataProvider validAppend
-     */
+    #[DataProvider('validAppend')]
     public function testAppend(string $raw, string $append, string $expected): void
     {
         self::assertSame($expected, (string) Domain::new($raw)->append($append));
@@ -378,9 +363,7 @@ public function testAppendNull(): void
         self::assertSame($domain->append(null), $domain);
     }
 
-    /**
-     * @dataProvider replaceValid
-     */
+    #[DataProvider('replaceValid')]
     public function testReplace(string $raw, string $input, int $offset, string $expected): void
     {
         self::assertSame($expected, (string) Domain::new($raw)->withLabel($offset, $input));
@@ -414,9 +397,7 @@ public function testReplaceMustFailed(): void
         Domain::new('secure.example.com')->withLabel(23, 'foo');
     }
 
-    /**
-     * @dataProvider rootProvider
-     */
+    #[DataProvider('rootProvider')]
     public function testWithRoot(string $host, string $expected_with_root, string $expected_without_root): void
     {
         $host = Domain::new($host);
@@ -433,9 +414,7 @@ public static function rootProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(Psr7UriInterface|UriInterface $uri, ?string $expected): void
     {
         $domain = Domain::fromUri($uri);
diff --git a/Components/FragmentTest.php b/Components/FragmentTest.php
index ff914402..e3746bf7 100644
--- a/Components/FragmentTest.php
+++ b/Components/FragmentTest.php
@@ -16,19 +16,14 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 use Stringable;
 
-/**
- * @group fragment
- * @coversDefaultClass \League\Uri\Components\Fragment
- */
 final class FragmentTest extends TestCase
 {
-    /**
-     * @dataProvider getUriComponentProvider
-     */
+    #[DataProvider('getUriComponentProvider')]
     public function testStringRepresentation(?string $str, string $encoded): void
     {
         self::assertSame($encoded, Fragment::new($str)->toString());
@@ -56,9 +51,7 @@ public static function getUriComponentProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider geValueProvider
-     */
+    #[DataProvider('getValueProvider')]
     public function testGetValue(Stringable|string|null $str, ?string $expected): void
     {
         if ($str instanceof UriComponentInterface) {
@@ -68,7 +61,7 @@ public function testGetValue(Stringable|string|null $str, ?string $expected): vo
         self::assertSame($expected, Fragment::new($str)->decoded());
     }
 
-    public static function geValueProvider(): array
+    public static function getValueProvider(): array
     {
         return [
             [Fragment::new(), null],
@@ -87,9 +80,7 @@ public static function geValueProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getContentProvider
-     */
+    #[DataProvider('getContentProvider')]
     public function testGetContent(string $input, string $expected): void
     {
         self::assertSame($expected, Fragment::new($input)->value());
@@ -129,9 +120,7 @@ public function testPreserverDelimiter(): void
         self::assertSame('', $fragment->toString());
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(Psr7UriInterface|UriInterface $uri, ?string $expected): void
     {
         $fragment = Fragment::fromUri($uri);
diff --git a/Components/HierarchicalPathTest.php b/Components/HierarchicalPathTest.php
index d8f75017..92814e54 100644
--- a/Components/HierarchicalPathTest.php
+++ b/Components/HierarchicalPathTest.php
@@ -17,16 +17,17 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 
 use function iterator_to_array;
 
-/**
- * @group path
- * @group hierarchicalpath
- * @coversDefaultClass \League\Uri\Components\HierarchicalPath
- */
+#[CoversClass(HierarchicalPath::class)]
+#[Group('path')]
+#[Group('hierarchicalpath')]
 final class HierarchicalPathTest extends TestCase
 {
     public function testIterator(): void
@@ -36,9 +37,7 @@ public function testIterator(): void
         self::assertEquals(['5.0', 'components', 'path'], iterator_to_array($path));
     }
 
-    /**
-     * @dataProvider validPathProvider
-     */
+    #[DataProvider('validPathProvider')]
     public function testValidPath(string $raw, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($raw));
@@ -69,9 +68,7 @@ public static function validPathProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider isAbsoluteProvider
-     */
+    #[DataProvider('isAbsoluteProvider')]
     public function testIsAbsolute(string $raw, bool $expected): void
     {
         $path = HierarchicalPath::new($raw);
@@ -89,9 +86,7 @@ public static function isAbsoluteProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getProvider
-     */
+    #[DataProvider('getProvider')]
     public function testget(string $raw, int $key, ?string $expected): void
     {
         self::assertSame($expected, HierarchicalPath::new($raw)->get($key));
@@ -110,9 +105,8 @@ public static function getProvider(): array
 
     /**
      * Test Removing Dot Segment.
-     *
-     * @dataProvider normalizeProvider
      */
+    #[DataProvider('normalizeProvider')]
     public function testWithoutDotSegments(string $path, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withoutDotSegments());
@@ -132,9 +126,7 @@ public static function normalizeProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withLeadingSlashProvider
-     */
+    #[DataProvider('withLeadingSlashProvider')]
     public function testWithLeadingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withLeadingSlash());
@@ -152,9 +144,7 @@ public static function withLeadingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withoutLeadingSlashProvider
-     */
+    #[DataProvider('withoutLeadingSlashProvider')]
     public function testWithoutLeadingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withoutLeadingSlash());
@@ -171,9 +161,7 @@ public static function withoutLeadingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider createFromRelativeSegmentsValid
-     */
+    #[DataProvider('createFromRelativeSegmentsValid')]
     public function testCreateRelativeFromSegments(iterable $input, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::fromRelative(...$input));
@@ -190,9 +178,7 @@ public static function createFromRelativeSegmentsValid(): array
         ];
     }
 
-    /**
-     * @dataProvider createFromAbsoluteSegmentsValid
-     */
+    #[DataProvider('createFromAbsoluteSegmentsValid')]
     public function testCreateAbsoluteFromSegments(iterable $input, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::fromAbsolute(...$input));
@@ -213,9 +199,7 @@ public static function createFromAbsoluteSegmentsValid(): array
         ];
     }
 
-    /**
-     * @dataProvider prependData
-     */
+    #[DataProvider('prependData')]
     public function testPrepend(string $source, string $prepend, string $res): void
     {
         self::assertSame($res, (string) HierarchicalPath::new($source)->prepend($prepend));
@@ -233,9 +217,7 @@ public static function prependData(): array
         ];
     }
 
-    /**
-     * @dataProvider appendData
-     */
+    #[DataProvider('appendData')]
     public function testAppend(string $source, string $append, string $res): void
     {
         self::assertSame($res, (string) HierarchicalPath::new($source)->append($append));
@@ -263,9 +245,7 @@ public function testWithSegmentUseAppend(): void
     }
 
 
-    /**
-     * @dataProvider withoutEmptySegmentsProvider
-     */
+    #[DataProvider('withoutEmptySegmentsProvider')]
     public function testWithoutEmptySegments(string $path, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withoutEmptySegments());
@@ -281,9 +261,7 @@ public static function withoutEmptySegmentsProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider replaceValid
-     */
+    #[DataProvider('replaceValid')]
     public function testReplace(string $raw, string $input, int $offset, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($raw)->withSegment($offset, $input));
@@ -315,10 +293,10 @@ public function testWithSegmentThrowsException(): void
     /**
      * Test AbstractSegment::without.
      *
-     * @dataProvider withoutProvider
      *
      * @param int[] $without
      */
+    #[DataProvider('withoutProvider')]
     public function testWithout(string $origin, array $without, string $result): void
     {
         self::assertSame($result, (string) HierarchicalPath::new($origin)->withoutSegment(...$without));
@@ -369,9 +347,7 @@ public function testSegments(): void
         self::assertSame([''], iterator_to_array(HierarchicalPath::new('/')));
     }
 
-    /**
-     * @dataProvider arrayProvider
-     */
+    #[DataProvider('arrayProvider')]
     public function testCountable(string $input, array $gets, int $nbSegment): void
     {
         $path = HierarchicalPath::new($input);
@@ -388,9 +364,7 @@ public static function arrayProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider provideBasenamePath
-     */
+    #[DataProvider('provideBasenamePath')]
     public function testGetBasemane(string $path, string $expected): void
     {
         self::assertSame($expected, HierarchicalPath::new($path)->getBasename());
@@ -415,9 +389,7 @@ public static function provideBasenamePath(): iterable
     }
 
 
-    /**
-     * @dataProvider dirnameProvider
-     */
+    #[DataProvider('dirnameProvider')]
     public function testGetDirmane(string $path, string $dirname): void
     {
         self::assertSame($dirname, HierarchicalPath::new($path)->getDirname());
@@ -437,9 +409,7 @@ public static function dirnameProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider extensionProvider
-     */
+    #[DataProvider('extensionProvider')]
     public function testGetExtension(string $raw, string $parsed): void
     {
         self::assertSame($parsed, HierarchicalPath::new($raw)->getExtension());
@@ -455,9 +425,7 @@ public static function extensionProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withExtensionProvider
-     */
+    #[DataProvider('withExtensionProvider')]
     public function testWithExtension(string $raw, string $raw_ext, string $new_path, string $parsed_ext): void
     {
         $newPath = HierarchicalPath::new($raw)->withExtension($raw_ext);
@@ -485,9 +453,7 @@ public static function withExtensionProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider invalidExtension
-     */
+    #[DataProvider('invalidExtension')]
     public function testWithExtensionWithInvalidExtension(string $extension): void
     {
         $this->expectException(SyntaxError::class);
@@ -504,9 +470,7 @@ public static function invalidExtension(): array
         ];
     }
 
-    /**
-     * @dataProvider withExtensionProvider2
-     */
+    #[DataProvider('withExtensionProvider2')]
     public function testWithExtensionPreserveTypeCode(string $uri, string $extension, string $expected): void
     {
         self::assertSame(
@@ -525,9 +489,7 @@ public static function withExtensionProvider2(): array
         ];
     }
 
-    /**
-     * @dataProvider getExtensionProvider
-     */
+    #[DataProvider('getExtensionProvider')]
     public function testGetExtensionPreserveTypeCode(string $uri, string $extension): void
     {
         self::assertSame($extension, HierarchicalPath::new($uri)->getExtension());
@@ -556,9 +518,7 @@ public static function geValueProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getDirnameProvider
-     */
+    #[DataProvider('getDirnameProvider')]
     public function testWithDirname(string $path, string $dirname, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withDirname($dirname));
@@ -600,9 +560,7 @@ public static function getDirnameProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getBasenameProvider
-     */
+    #[DataProvider('getBasenameProvider')]
     public function testWithBasename(string $path, string $basename, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withBasename($basename));
@@ -639,9 +597,7 @@ public static function getBasenameProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider basenameInvalidProvider
-     */
+    #[DataProvider('basenameInvalidProvider')]
     public function testWithBasenameThrowException(string $path): void
     {
         $this->expectException(SyntaxError::class);
@@ -657,9 +613,7 @@ public static function basenameInvalidProvider(): array
     }
 
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(Psr7UriInterface|UriInterface $uri, ?string $expected): void
     {
         $path = HierarchicalPath::fromUri($uri);
@@ -706,9 +660,7 @@ public function testCreateFromUriWithPSR7Implementation(): void
         self::assertSame('/path', HierarchicalPath::fromUri($uri)->toString());
     }
 
-    /**
-     * @dataProvider trailingSlashProvider
-     */
+    #[DataProvider('trailingSlashProvider')]
     public function testHasTrailingSlash(string $path, bool $expected): void
     {
         self::assertSame($expected, HierarchicalPath::new($path)->hasTrailingSlash());
@@ -726,9 +678,7 @@ public static function trailingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withTrailingSlashProvider
-     */
+    #[DataProvider('withTrailingSlashProvider')]
     public function testWithTrailingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withTrailingSlash());
@@ -746,9 +696,7 @@ public static function withTrailingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withoutTrailingSlashProvider
-     */
+    #[DataProvider('withoutTrailingSlashProvider')]
     public function testWithoutTrailingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) HierarchicalPath::new($path)->withoutTrailingSlash());
@@ -766,9 +714,7 @@ public static function withoutTrailingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validPathEncoding
-     */
+    #[DataProvider('validPathEncoding')]
     public function testGetUriComponent(string $decoded, string $encoded): void
     {
         $path = HierarchicalPath::new($decoded);
diff --git a/Components/HostTest.php b/Components/HostTest.php
index b7df5c73..53ad8272 100644
--- a/Components/HostTest.php
+++ b/Components/HostTest.php
@@ -19,6 +19,9 @@
 use League\Uri\Idna\Error;
 use League\Uri\Idna\Result;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 use Stringable;
@@ -26,17 +29,14 @@
 use function array_fill;
 use function implode;
 
-/**
- * @group host
- * @coversDefaultClass \League\Uri\Components\Host
- */
+#[CoversClass(Host::class)]
+#[Group('host')]
 final class HostTest extends TestCase
 {
     /**
      * Test valid Host.
-     *
-     * @dataProvider validHostProvider
      */
+    #[DataProvider('validHostProvider')]
     public function testValidHost(Stringable|int|string|null $host, ?string $uri, ?string $iri): void
     {
         $host = match (true) {
@@ -126,9 +126,7 @@ public static function validHostProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider invalidHostProvider
-     */
+    #[DataProvider('invalidHostProvider')]
     public function testInvalidHost(string $invalid): void
     {
         $this->expectException(SyntaxError::class);
@@ -174,9 +172,8 @@ public function testInvalidi18nConversionReturnsErrors(): void
 
     /**
      * Test Punycode support.
-     *
-     * @dataProvider hostnamesProvider
      */
+    #[DataProvider('hostnamesProvider')]
     public function testValidUnicodeHost(string $unicode, string $ascii): void
     {
         $host = Host::new($unicode);
@@ -213,9 +210,7 @@ public static function hostnamesProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(Psr7UriInterface|UriInterface $uri, ?string $expected): void
     {
         $host = Host::fromUri($uri);
@@ -253,9 +248,7 @@ public static function getURIProvider(): iterable
         ];
     }
 
-    /**
-     * @dataProvider getIsDomainProvider
-     */
+    #[DataProvider('getIsDomainProvider')]
     public function test_host_is_domain(?string $host, bool $expectedIsDomain): void
     {
         $host = null !== $host ? Host::new($host) : Host::new();
@@ -273,67 +266,54 @@ public static function getIsDomainProvider(): iterable
             'registered named' => [
                 'host' => '-registered-.name',
                 'expectedIsDomain' => false,
-                'isRegisteredName' => true,
             ],
             'ipv4 host' => [
                 'host' => '127.0.0.1',
                 'expectedIsDomain' => false,
-                'isRegisteredName' => false,
             ],
             'ipv6 host' => [
                 'host' => '[::1]',
                 'expectedIsDomain' => false,
-                'isRegisteredName' => false,
             ],
             'too long domain name' => [
                 'host' => $tooLongHost,
                 'expectedIsDomain' => false,
-                'isRegisteredName' => true,
             ],
             'single label domain' => [
                 'host' => 'localhost',
                 'expectedIsDomain' => true,
-                'isRegisteredName' => true,
             ],
             'single label domain with ending dot' => [
                 'host' => 'localhost.',
                 'expectedIsDomain' => true,
-                'isRegisteredName' => true,
             ],
             'longest domain name' => [
                 'host' => $maxLongHost,
                 'expectedIsDomain' => true,
-                'isRegisteredName' => true,
             ],
             'longest domain name with ending dot' => [
                 'host' => $maxLongHost.'.',
                 'expectedIsDomain' => true,
-                'isRegisteredName' => true,
             ],
             'too long label' => [
                 'host' => $tooLongLabel,
                 'expectedIsDomain' => false,
-                'isRegisteredName' => true,
             ],
             'empty string host' => [
                 'host' => '',
                 'expectedIsDomain' => false,
-                'isRegisteredName' => true,
             ],
             'single dot' => [
                 'host' => '.',
                 'expectedIsDomain' => false,
-                'isRegisteredName' => true,
             ],
             'null string host' => [
                 'host' => null,
                 'expectedIsDomain' => true,
-                'isRegisteredName' => true,
             ],
             'multiple domain with a dot ending' => [
                 'host' => 'ulb.ac.be.',
                 'expectedIsDomain' => true,
-                'isRegisteredName' => true,
             ],
         ];
     }
diff --git a/Components/IpAddressTest.php b/Components/IpAddressTest.php
index 98fe01a2..a77a0707 100644
--- a/Components/IpAddressTest.php
+++ b/Components/IpAddressTest.php
@@ -15,15 +15,11 @@
 use PHPUnit\Framework\TestCase;
 use Stringable;
 
-/**
- * @group host
- * @coversDefaultClass \League\Uri\Components\Host
- */
+#[\PHPUnit\Framework\Attributes\CoversClass(\League\Uri\Components\Host::class)]
+#[\PHPUnit\Framework\Attributes\Group('host')]
 final class IpAddressTest extends TestCase
 {
-    /**
-     * @dataProvider validIpAddressProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validIpAddressProvider')]
     public function testValidIpAddress(
         Stringable|int|string|null $host,
         bool $isDomain,
@@ -125,9 +121,7 @@ public static function validIpAddressProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider createFromIpValid
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('createFromIpValid')]
     public function testCreateFromIp(string $input, string $version, string $expected): void
     {
         self::assertSame($expected, (string) Host::fromIp($input, $version));
@@ -146,9 +140,7 @@ public static function createFromIpValid(): array
         ];
     }
 
-    /**
-     * @dataProvider createFromIpFailed
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('createFromIpFailed')]
     public function testCreateFromIpFailed(string $input): void
     {
         $this->expectException(SyntaxError::class);
@@ -165,9 +157,7 @@ public static function createFromIpFailed(): array
         ];
     }
 
-    /**
-     * @dataProvider withoutZoneIdentifierProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('withoutZoneIdentifierProvider')]
     public function testWithoutZoneIdentifier(string $host, string $expected): void
     {
         self::assertSame($expected, (string) Host::new($host)->withoutZoneIdentifier());
@@ -183,9 +173,7 @@ public static function withoutZoneIdentifierProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider hasZoneIdentifierProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('hasZoneIdentifierProvider')]
     public function testHasZoneIdentifier(string $host, bool $expected): void
     {
         self::assertSame($expected, Host::new($host)->hasZoneIdentifier());
diff --git a/Components/PathTest.php b/Components/PathTest.php
index 1dc3872a..28ce3997 100644
--- a/Components/PathTest.php
+++ b/Components/PathTest.php
@@ -15,19 +15,18 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 
-/**
- * @group path
- * @group defaultpath
- * @coversDefaultClass \League\Uri\Components\Path
- */
+#[CoversClass(Path::class)]
+#[Group('path')]
+#[Group('defaultpath')]
 final class PathTest extends TestCase
 {
-    /**
-     * @dataProvider validPathEncoding
-     */
+    #[DataProvider('validPathEncoding')]
     public function testGetUriComponent(string $decoded, string $encoded): void
     {
         $path = Path::new($decoded);
@@ -107,9 +106,8 @@ public function testConstructorThrowsExceptionWithInvalidData(): void
 
     /**
      * Test Removing Dot Segment.
-     *
-     * @dataProvider normalizeProvider
      */
+    #[DataProvider('normalizeProvider')]
     public function testWithoutDotSegments(string $path, string $expected): void
     {
         self::assertSame($expected, Path::new($path)->withoutDotSegments()->toString());
@@ -129,9 +127,7 @@ public static function normalizeProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider trailingSlashProvider
-     */
+    #[DataProvider('trailingSlashProvider')]
     public function testHasTrailingSlash(string $path, bool $expected): void
     {
         self::assertSame($expected, Path::new($path)->hasTrailingSlash());
@@ -149,9 +145,7 @@ public static function trailingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withTrailingSlashProvider
-     */
+    #[DataProvider('withTrailingSlashProvider')]
     public function testWithTrailingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) Path::new($path)->withTrailingSlash());
@@ -169,9 +163,7 @@ public static function withTrailingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withoutTrailingSlashProvider
-     */
+    #[DataProvider('withoutTrailingSlashProvider')]
     public function testWithoutTrailingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) Path::new($path)->withoutTrailingSlash());
@@ -189,9 +181,7 @@ public static function withoutTrailingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withLeadingSlashProvider
-     */
+    #[DataProvider('withLeadingSlashProvider')]
     public function testWithLeadingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) Path::new($path)->withLeadingSlash());
@@ -209,9 +199,7 @@ public static function withLeadingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider withoutLeadingSlashProvider
-     */
+    #[DataProvider('withoutLeadingSlashProvider')]
     public function testWithoutLeadingSlash(string $path, string $expected): void
     {
         self::assertSame($expected, (string) Path::new($path)->withoutLeadingSlash());
@@ -228,9 +216,7 @@ public static function withoutLeadingSlashProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(Psr7UriInterface|UriInterface $uri, ?string $expected): void
     {
         $path = Path::fromUri($uri);
diff --git a/Components/PortTest.php b/Components/PortTest.php
index 456e8b62..ca0574b1 100644
--- a/Components/PortTest.php
+++ b/Components/PortTest.php
@@ -15,14 +15,15 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 use Stringable;
 
-/**
- * @group port
- * @coversDefaultClass \League\Uri\Components\Port
- */
+#[CoversClass(Port::class)]
+#[Group('port')]
 final class PortTest extends TestCase
 {
     public function testPortSetter(): void
@@ -30,9 +31,7 @@ public function testPortSetter(): void
         self::assertSame('443', Port::new(443)->toString());
     }
 
-    /**
-     * @dataProvider getToIntProvider
-     */
+    #[DataProvider('getToIntProvider')]
     public function testToInt(
         Stringable|int|string|null $input,
         ?int $expected,
@@ -69,9 +68,7 @@ public function testFailedPortException(): void
         Port::new(-1);
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(UriInterface|Psr7UriInterface $uri, ?string $expected): void
     {
         $port = Port::fromUri($uri);
diff --git a/Components/QueryTest.php b/Components/QueryTest.php
index aa52e89e..7933088d 100644
--- a/Components/QueryTest.php
+++ b/Components/QueryTest.php
@@ -16,16 +16,17 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 use Stringable;
 
 use function json_encode;
 
-/**
- * @group query
- * @coversDefaultClass \League\Uri\Components\Query
- */
+#[CoversClass(Query::class)]
+#[Group('query')]
 final class QueryTest extends TestCase
 {
     protected Query $query;
@@ -121,9 +122,7 @@ public function testNormalization(): void
         self::assertSame($this->query, $this->query->withoutEmptyPairs());
     }
 
-    /**
-     * @dataProvider validAppendValue
-     */
+    #[DataProvider('validAppendValue')]
     public function testAppend(?string $query, Stringable|string|null $appendData, ?string $expected): void
     {
         self::assertSame($expected, Query::new($query)->append($appendData)->value());
@@ -197,9 +196,7 @@ public function testParams(): void
         self::assertNull($query->parameter('foo[]'));
     }
 
-    /**
-     * @dataProvider withoutKeyPairProvider
-     */
+    #[DataProvider('withoutKeyPairProvider')]
     public function testwithoutKeyPair(string $origin, array $without, string $result): void
     {
         self::assertSame($result, (string) Query::new($origin)->withoutPairByKey(...$without));
@@ -241,10 +238,9 @@ public function testwithoutKeyPairGetterMethod(): void
     }
 
     /**
-     * @dataProvider providePairsValuesToBeRemoved
-     *
      * @param list<Stringable|string|int|bool|null> $values
      */
+    #[DataProvider('providePairsValuesToBeRemoved')]
     public function testWithoutPairByValue(string $query, array $values, string $expected): void
     {
         self::assertSame($expected, Query::fromRFC3986($query)->withoutPairByValue(...$values)->value());
@@ -296,10 +292,9 @@ public static function providePairsValuesToBeRemoved(): iterable
     }
 
     /**
-     * @dataProvider providePairsToBeRemoved
-     *
      * @param list{0:string, 1:Stringable|string|int|bool|null} $pair
      */
+    #[DataProvider('providePairsToBeRemoved')]
     public function testWithoutPairByKeyValue(string $query, array $pair, string $expected): void
     {
         self::assertSame($expected, Query::fromRFC3986($query)->withoutPairByKeyValue(...$pair)->value());
@@ -344,9 +339,7 @@ public static function providePairsToBeRemoved(): iterable
         ];
     }
 
-    /**
-     * @dataProvider withoutParamProvider
-     */
+    #[DataProvider('withoutParamProvider')]
     public function testwithoutParam(array $origin, array $without, string $expected): void
     {
         self::assertSame($expected, Query::fromVariable($origin)->withoutParameters(...$without)->toString());
@@ -544,9 +537,7 @@ public static function testSort(): void
         self::assertNotEquals($sortedQuery, $query);
     }
 
-    /**
-     * @dataProvider sameQueryAfterSortingProvider
-     */
+    #[DataProvider('sameQueryAfterSortingProvider')]
     public function testSortReturnSameInstance(?string $query): void
     {
         $query = Query::new($query);
@@ -563,9 +554,7 @@ public static function sameQueryAfterSortingProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider provideWithPairData
-     */
+    #[DataProvider('provideWithPairData')]
     public function testWithPair(?string $query, string $key, string|null|bool $value, array $expected): void
     {
         self::assertSame($expected, Query::new($query)->withPair($key, $value)->getAll($key));
@@ -608,9 +597,7 @@ public function testWithPairBasic(): void
         self::assertSame('a=b&c=d&e=f', Query::new('a=b&c=d')->withPair('e', 'f')->toString());
     }
 
-    /**
-     * @dataProvider mergeBasicProvider
-     */
+    #[DataProvider('mergeBasicProvider')]
     public function testMergeBasic(string $src, Stringable|string|null $dest, string $expected): void
     {
         self::assertSame($expected, Query::new($src)->merge($dest)->toString());
@@ -682,9 +669,7 @@ public function testMergeGetterMethods(): void
         self::assertSame('a=4&first=4', $query->get('q'));
     }
 
-    /**
-     * @dataProvider provideWithoutDuplicatesData
-     */
+    #[DataProvider('provideWithoutDuplicatesData')]
     public function testWithoutDuplicates(?string $query, ?string $expected): void
     {
         self::assertSame($expected, Query::new($query)->withoutDuplicates()->value());
@@ -749,9 +734,7 @@ public function testAppendToWithGetter(): void
         self::assertSame('1', $newQuery->get('first'));
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(Psr7UriInterface|UriInterface $uri, ?string $expected): void
     {
         self::assertSame($expected, Query::fromUri($uri)->value());
diff --git a/Components/SchemeTest.php b/Components/SchemeTest.php
index a0bfe32f..e6c0a8fd 100644
--- a/Components/SchemeTest.php
+++ b/Components/SchemeTest.php
@@ -15,14 +15,15 @@
 use League\Uri\Exceptions\SyntaxError;
 use League\Uri\Http;
 use League\Uri\Uri;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 use Stringable;
 
-/**
- * @group scheme
- * @coversDefaultClass \League\Uri\Components\Scheme
- */
+#[CoversClass(Scheme::class)]
+#[Group('scheme')]
 final class SchemeTest extends TestCase
 {
     public function testWithContent(): void
@@ -30,9 +31,7 @@ public function testWithContent(): void
         self::assertEquals(Scheme::new('ftp'), Scheme::new('FtP'));
     }
 
-    /**
-     * @dataProvider validSchemeProvider
-     */
+    #[DataProvider('validSchemeProvider')]
     public function testValidScheme(
         Stringable|string|null $scheme,
         string $toString,
@@ -63,9 +62,7 @@ public function __toString(): string
         ];
     }
 
-    /**
-     * @dataProvider invalidSchemeProvider
-     */
+    #[DataProvider('invalidSchemeProvider')]
     public function testInvalidScheme(string $scheme): void
     {
         $this->expectException(SyntaxError::class);
@@ -82,9 +79,7 @@ public static function invalidSchemeProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(UriInterface|Psr7UriInterface $uri, ?string $expected): void
     {
         self::assertSame($expected, Scheme::fromUri($uri)->value());
diff --git a/Components/URLSearchParamsTest.php b/Components/URLSearchParamsTest.php
index 9b53dddd..f20e8399 100644
--- a/Components/URLSearchParamsTest.php
+++ b/Components/URLSearchParamsTest.php
@@ -17,6 +17,7 @@
 use DateInterval;
 use IteratorAggregate;
 use League\Uri\Exceptions\SyntaxError;
+use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\TestCase;
 use stdClass;
 use Stringable;
@@ -163,9 +164,7 @@ public function testNewInstanceWithSequenceOfSequencesOfString(): void
         self::assertSame('d', $params->get('c'));
     }
 
-    /**
-     * @dataProvider providesInvalidSequenceOfSequencesOfString
-     */
+    #[DataProvider('providesInvalidSequenceOfSequencesOfString')]
     public function testNewInstanceWithSequenceOfSequencesOfStringFails(array $sequences): void
     {
         $this->expectException(SyntaxError::class);
@@ -185,9 +184,7 @@ public static function providesInvalidSequenceOfSequencesOfString(): iterable
         ];
     }
 
-    /**
-     * @dataProvider providesComplexConstructorData
-     */
+    #[DataProvider('providesComplexConstructorData')]
     public function testComplexConstructor(string $json): void
     {
         /** @var object{input: string, output: array<array{0: string, 1: string}>, name: string} $res */
@@ -582,9 +579,7 @@ public function testNoNormalizationForCarriageReturnCharacters(): void
         self::assertSame($params->toString(), 'a%0Ab=c%0Dd&e%0A%0Df=g%0D%0Ah');
     }
 
-    /**
-     * @dataProvider provideSortingPayload
-     */
+    #[DataProvider('provideSortingPayload')]
     public function testSorting(string $input, array $output): void
     {
         $params = new URLSearchParams($input);
@@ -819,9 +814,8 @@ public function testFromParametersRespectURLSpecTypeConversion(): void
 
     /**
      * @see https://github.com/php/php-src/tree/master/ext/standard/tests/http/http_build_query
-     *
-     * @dataProvider providesParametersInput
      */
+    #[DataProvider('providesParametersInput')]
     public function testFromParametersWithDifferentInput(object|array $data, string $expected): void
     {
         self::assertSame($expected, URLSearchParams::fromVariable($data)->toString());
diff --git a/Components/UserInfoTest.php b/Components/UserInfoTest.php
index ab7e425c..42a2adbe 100644
--- a/Components/UserInfoTest.php
+++ b/Components/UserInfoTest.php
@@ -16,19 +16,18 @@
 use League\Uri\Http;
 use League\Uri\Uri;
 use League\Uri\UriString;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UriInterface as Psr7UriInterface;
 use Stringable;
 
-/**
- * @group userinfo
- * @coversDefaultClass \League\Uri\Components\UserInfo
- */
+#[CoversClass(UserInfo::class)]
+#[Group('userinfo')]
 final class UserInfoTest extends TestCase
 {
-    /**
-     * @dataProvider userInfoProvider
-     */
+    #[DataProvider('userInfoProvider')]
     public function testConstructor(
         Stringable|string|null $user,
         Stringable|string|null $pass,
@@ -153,9 +152,7 @@ public function testWithContentReturnSameInstance(): void
         );
     }
 
-    /**
-     * @dataProvider withUserInfoProvider
-     */
+    #[DataProvider('withUserInfoProvider')]
     public function testWithUserInfo(?string $user, ?string $pass, ?string $expected): void
     {
         self::assertSame($expected, UserInfo::new()->withUser($user)->withPass($pass)->toString());
@@ -187,9 +184,7 @@ public function testConstructorThrowsException(): void
         new UserInfo("\0");
     }
 
-    /**
-     * @dataProvider getURIProvider
-     */
+    #[DataProvider('getURIProvider')]
     public function testCreateFromUri(UriInterface|Psr7UriInterface $uri, ?string $expected): void
     {
         $userInfo = UserInfo::fromUri($uri);
@@ -263,10 +258,9 @@ public function testItFailsToCreateANewInstanceWhenTheUsernameIsUndefined(): voi
     }
 
     /**
-     * @dataProvider providesUriToParse
-     *
      * @param array{user: ?string, pass: ?string} $components
      */
+    #[DataProvider('providesUriToParse')]
     public function testNewInstanceFromUriParsing(string $uri, ?string $expected, array $components): void
     {
         $userInfo = UserInfo::fromComponents(UriString::parse($uri));
diff --git a/ModifierTest.php b/ModifierTest.php
index deef6aeb..4ff6ee33 100644
--- a/ModifierTest.php
+++ b/ModifierTest.php
@@ -14,15 +14,15 @@
 use GuzzleHttp\Psr7\Utils;
 use League\Uri\Components\DataPath;
 use League\Uri\Exceptions\SyntaxError;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\Group;
 use PHPUnit\Framework\TestCase;
 
 use const PHP_QUERY_RFC3986;
 
-/**
- * @group host
- * @group resolution
- * @coversDefaultClass \League\Uri\UriModifier
- */
+#[CoversClass(UriModifier::class)] /** @phpstan-ignore-line */
+#[Group('host')]
+#[Group('resolution')]
 final class ModifierTest extends TestCase
 {
     private readonly string $uri;
@@ -37,10 +37,7 @@ protected function setUp(): void
     /*****************************
      * QUERY MODIFIER METHOD TESTS
      ****************************/
-
-    /**
-     * @dataProvider validMergeQueryProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validMergeQueryProvider')]
     public function testMergeQuery(string $query, string $expected): void
     {
         self::assertSame($expected, $this->modifier->mergeQuery($query)->getUri()->getQuery());
@@ -54,9 +51,7 @@ public static function validMergeQueryProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validMergeQueryPairsProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validMergeQueryPairsProvider')]
     public function testMergeQueryPairs(iterable $pairs, string $expected): void
     {
         self::assertSame($expected, $this->modifier->mergeQueryPairs($pairs)->getUri()->getQuery());
@@ -76,9 +71,7 @@ public static function validMergeQueryPairsProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validMergeQueryParametersProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validMergeQueryParametersProvider')]
     public function testMergeQueryParameters(iterable $parameters, string $expected): void
     {
         self::assertSame($expected, $this->modifier->mergeQueryParameters($parameters)->getUri()->getQuery());
@@ -102,9 +95,7 @@ public static function validMergeQueryParametersProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validAppendQueryProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validAppendQueryProvider')]
     public function testAppendQuery(string $query, string $expected): void
     {
         self::assertSame($expected, $this->modifier->appendQuery($query)->getUri()->getQuery());
@@ -118,9 +109,7 @@ public static function validAppendQueryProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validAppendQueryPairsProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validAppendQueryPairsProvider')]
     public function testAppendQueryPairs(iterable $query, string $expected): void
     {
         self::assertSame($expected, $this->modifier->appendQueryPairs($query)->getUri()->getQuery());
@@ -140,9 +129,7 @@ public static function validAppendQueryPairsProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validAppendQueryParametersProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validAppendQueryParametersProvider')]
     public function testAppendQueryParameters(iterable $query, string $expected): void
     {
         self::assertSame($expected, $this->modifier->appendQueryParameters($query)->getUri()->getQuery());
@@ -168,9 +155,7 @@ public function testKsortQuery(): void
         self::assertSame('foo=bar%20baz&kingkong=toto&kingkong=ape', Modifier::from($uri)->sortQuery()->getUri()->getQuery());
     }
 
-    /**
-     * @dataProvider validWithoutQueryValuesProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validWithoutQueryValuesProvider')]
     public function testWithoutQueryValuesProcess(array $input, string $expected): void
     {
         self::assertSame($expected, $this->modifier->removeQueryPairsByKey(...$input)->getUri()->getQuery());
@@ -184,9 +169,7 @@ public static function validWithoutQueryValuesProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validWithoutQueryPairByValueProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validWithoutQueryPairByValueProvider')]
     public function testvalidWithoutQueryPairByValue(array $values, string $expected): void
     {
         self::assertSame($expected, $this->modifier->removeQueryPairsByValue(...$values)->getUri()->getQuery());
@@ -200,9 +183,7 @@ public static function validWithoutQueryPairByValueProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validWithoutQueryPairByKeyValueProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validWithoutQueryPairByKeyValueProvider')]
     public function testvalidWithoutQueryPairByKeyValue(array $values, string $expected): void
     {
         self::assertSame($expected, $this->modifier->removeQueryPairsByKeyValue(...$values)->getUri()->getQuery());
@@ -217,9 +198,7 @@ public static function validWithoutQueryPairByKeyValueProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider removeParamsProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('removeParamsProvider')]
     public function testWithoutQueryParams(string $uri, array $input, ?string $expected): void
     {
         self::assertSame($expected, Modifier::from($uri)->removeQueryParameters(...$input)->getUri()->getQuery());
@@ -246,9 +225,7 @@ public static function removeParamsProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider removeQueryParameterIndicesProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('removeQueryParameterIndicesProvider')]
     public function testWithoutQueryParameterIndices(string $uri, string $expected): void
     {
         self::assertSame($expected, Modifier::from($uri)->removeQueryParameterIndices()->getUri()->getQuery());
@@ -272,9 +249,7 @@ public static function removeQueryParameterIndicesProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider removeEmptyPairsProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('removeEmptyPairsProvider')]
     public function testRemoveEmptyPairs(string $uri, ?string $expected): void
     {
         self::assertSame($expected, Modifier::from(Uri::fromBaseUri($uri))->removeEmptyQueryPairs()->getUri()->__toString());
@@ -327,26 +302,19 @@ public function testEncodeQuery(): void
     /*****************************
      * HOST MODIFIER METHOD TESTS
      ****************************/
-
-    /**
-     * @dataProvider validHostProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validHostProvider')]
     public function testPrependLabelProcess(string $label, int $key, string $prepend, string $append, string $replace): void
     {
         self::assertSame($prepend, $this->modifier->prependLabel($label)->getUri()->getHost());
     }
 
-    /**
-     * @dataProvider validHostProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validHostProvider')]
     public function testAppendLabelProcess(string $label, int $key, string $prepend, string $append, string $replace): void
     {
         self::assertSame($append, $this->modifier->appendLabel($label)->getUri()->getHost());
     }
 
-    /**
-     * @dataProvider validHostProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validHostProvider')]
     public function testReplaceLabelProcess(string $label, int $key, string $prepend, string $append, string $replace): void
     {
         self::assertSame($replace, $this->modifier->replaceLabel($key, $label)->getUri()->getHost());
@@ -435,9 +403,7 @@ public function testWithoutZoneIdentifierProcess(): void
         );
     }
 
-    /**
-     * @dataProvider validwithoutLabelProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validwithoutLabelProvider')]
     public function testwithoutLabelProcess(array $keys, string $expected): void
     {
         self::assertSame($expected, $this->modifier->removeLabels(...$keys)->getUri()->getHost());
@@ -553,18 +519,13 @@ public function testIpv4NormalizeHostWithLeagueUri(): void
     /*********************
      * PATH MODIFIER TESTS
      *********************/
-
-    /**
-     * @dataProvider fileProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('fileProvider')]
     public function testToBinary(Uri $binary, Uri $ascii): void
     {
         self::assertSame($binary->toString(), Modifier::from($ascii)->dataPathToBinary()->getUriString());
     }
 
-    /**
-     * @dataProvider fileProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('fileProvider')]
     public function testToAscii(Uri $binary, Uri $ascii): void
     {
         self::assertSame($ascii->toString(), Modifier::from($binary)->dataPathToAscii()->getUriString());
@@ -598,9 +559,7 @@ public function testDataUriWithParameters(): void
         );
     }
 
-    /**
-     * @dataProvider appendSegmentProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('appendSegmentProvider')]
     public function testAppendProcess(string $segment, string $append): void
     {
         self::assertSame($append, $this->modifier->appendSegment($segment)->getUri()->getPath());
@@ -614,9 +573,7 @@ public static function appendSegmentProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validAppendSegmentProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validAppendSegmentProvider')]
     public function testAppendProcessWithRelativePath(string $uri, string $segment, string $expected): void
     {
         self::assertSame($expected, (string) Modifier::from($uri)->appendSegment($segment)->getUri());
@@ -648,9 +605,7 @@ public static function validAppendSegmentProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider validBasenameProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validBasenameProvider')]
     public function testBasename(string $path, string $uri, string $expected): void
     {
         self::assertSame($expected, (string) Modifier::from(Uri::new($uri))->replaceBasename($path));
@@ -673,9 +628,7 @@ public function testBasenameThrowException(): void
         Modifier::from(Uri::new('http://example.com'))->replaceBasename('foo/baz');
     }
 
-    /**
-     * @dataProvider validDirnameProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validDirnameProvider')]
     public function testDirname(string $path, string $uri, string $expected): void
     {
         self::assertSame($expected, (string) Modifier::from(Uri::new($uri))->replaceDirname($path));
@@ -691,13 +644,11 @@ public static function validDirnameProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider prependSegmentProvider
-     */
-    public function testPrependProcess(string $uri, string $segment, string $prepend): void
+    #[\PHPUnit\Framework\Attributes\DataProvider('prependSegmentProvider')]
+    public function testPrependProcess(string $uri, string $segment, string $expectedPath): void
     {
         $uri = Uri::new($uri);
-        self::assertSame($prepend, Modifier::from($uri)->prependSegment($segment)->getUri()->getPath());
+        self::assertSame($expectedPath, Modifier::from($uri)->prependSegment($segment)->getUri()->getPath());
     }
 
     public static function prependSegmentProvider(): array
@@ -726,9 +677,7 @@ public static function prependSegmentProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider replaceSegmentProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('replaceSegmentProvider')]
     public function testReplaceSegmentProcess(string $segment, int $key, string $append, string $prepend, string $replace): void
     {
         self::assertSame($replace, $this->modifier->replaceSegment($key, $segment)->getUri()->getPath());
@@ -742,9 +691,7 @@ public static function replaceSegmentProvider(): array
         ];
     }
 
-    /**
-     * @dataProvider addBasepathProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('addBasepathProvider')]
     public function testaddBasepath(string $basepath, string $expected): void
     {
         self::assertSame($expected, $this->modifier->addBasePath($basepath)->getUri()->getPath());
@@ -766,9 +713,7 @@ public function testaddBasepathWithRelativePath(): void
         self::assertSame('/base/path', Modifier::from($uri)->addBasePath('/base/path')->getUri()->getPath());
     }
 
-    /**
-     * @dataProvider removeBasePathProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('removeBasePathProvider')]
     public function testRemoveBasePath(string $basepath, string $expected): void
     {
         self::assertSame($expected, $this->modifier->removeBasePath($basepath)->getUri()->getPath());
@@ -790,9 +735,7 @@ public function testRemoveBasePathWithRelativePath(): void
         self::assertSame('base/path', Modifier::from($uri)->removeBasePath('/base/path')->getUri()->getPath());
     }
 
-    /**
-     * @dataProvider validwithoutSegmentProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validwithoutSegmentProvider')]
     public function testwithoutSegment(array $keys, string $expected): void
     {
         self::assertSame($expected, $this->modifier->removeSegments(...$keys)->getUri()->getPath());
@@ -827,9 +770,7 @@ public function testWithoutTrailingSlashProcess(): void
         self::assertSame('', Modifier::from($uri)->removeTrailingSlash()->getUri()->getPath());
     }
 
-    /**
-     * @dataProvider validExtensionProvider
-     */
+    #[\PHPUnit\Framework\Attributes\DataProvider('validExtensionProvider')]
     public function testExtensionProcess(string $extension, string $expected): void
     {
         self::assertSame($expected, $this->modifier->replaceExtension($extension)->getUri()->getPath());
diff --git a/UriModifierTest.php b/UriModifierTest.php
index 0d5ec37e..7f91b3df 100644
--- a/UriModifierTest.php
+++ b/UriModifierTest.php
@@ -13,11 +13,12 @@
 
 namespace League\Uri;
 
+use PHPUnit\Framework\Attributes\Test;
 use PHPUnit\Framework\TestCase;
 
 final class UriModifierTest extends TestCase
 {
-    /** @test */
+    #[Test]
     public function it_will_remove_empty_pairs_fix_issue_133(): void
     {
         $removeEmptyPairs = fn (string $str): ?string => UriModifier::removeEmptyPairs(Http::createFromString($str))->getQuery(); /* @phpstan-ignore-line */