Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support PHP 8 attributes for adding metadata to test classes and test methods as well as tested code units #4502

Closed
sebastianbergmann opened this issue Oct 30, 2020 · 0 comments
Assignees
Labels
type/enhancement A new idea that should be implemented
Milestone

Comments

@sebastianbergmann
Copy link
Owner

sebastianbergmann commented Oct 30, 2020

PHPUnit currently supports the following annotations in special PHP comments ("DocBlocks", "doc-comments"):

  • @after
  • @afterClass
  • @backupGlobals enabled and @backupGlobals disabled
  • @backupStaticAttributes enabled and @backupStaticAttributes disabled
  • @before
  • @beforeClass
  • @codeCoverageIgnore
  • @covers ::functionName
  • @covers ClassName
  • @covers ClassName::methodName (not recommended because too fine-grained)
  • @covers ClassName<extended> (deprecated; will be removed in PHPUnit 10)
  • @covers ClassName::<public> (deprecated; will be removed in PHPUnit 10)
  • @covers ClassName::<protected> (deprecated; will be removed in PHPUnit 10)
  • @covers ClassName::<private> (deprecated; will be removed in PHPUnit 10)
  • @covers ClassName::<!public> (deprecated; will be removed in PHPUnit 10)
  • @covers ClassName::<!protected> (deprecated; will be removed in PHPUnit 10)
  • @covers ClassName::<!private> (deprecated; will be removed in PHPUnit 10)
  • @coversDefaultClass ClassName
  • @coversNothing
  • @dataProvider methodName
  • @dataProvider ClassName::methodName
  • @depends methodName
  • @depends clone methodName
  • @depends shallowClone methodName
  • @depends ClassName::methodName
  • @depends clone ClassName::methodName
  • @depends !clone ClassName::methodName
  • @depends shallowClone ClassName::methodName
  • @depends !shallowClone ClassName::methodName
  • @depends ClassName::class
  • @depends clone ClassName::class
  • @depends !clone ClassName::class
  • @depends shallowClone ClassName::class
  • @depends !shallowClone ClassName::class
  • @doesNotPerformAssertions
  • @group string
  • @small (as alias for @group small)
  • @medium (as alias for @group medium)
  • @large (as alias for @group large)
  • @author string (as alias for @group <string>)
  • @ticket string (as alias for @group <string>)
  • @preCondition
  • @postCondition
  • @preserveGlobalState enabled and @preserveGlobalState disabled
  • @requires PHPUnit <version requirement>
  • @requires PHP <version requirement>
  • @requires extension <extension> <version requirement> (where <version requirement> is optional)
  • @requires function <function> (where <function> is passed to function_exists())
  • @requires function <class>::<method> (where <class> and <method> are passed to method_exists())
  • @requires setting <setting> <value> (where <setting> is a configuration setting that can be queried with ini_set() for comparison with <value>)
  • @requires OS <os> (where <os> is a regular expression that is applied to PHP_OS)
  • @requires OSFAMILY <family> (where <family> is compared to PHP_OS_FAMILY)
  • @runTestsInSeparateProcesses
  • @runInSeparateProcess
  • @test
  • @testdox string
  • @testWith string
  • @uses ::functionName
  • @uses ClassName
  • @uses ClassName::methodName (not recommended because too fine-grained)

PHP 8 introduced attributes as

"a form of structured, syntactic metadata to declarations of classes, properties, functions, methods, parameters and constants. Attributes allow to define configuration directives directly embedded with the declaration of that code."

Support for attributes in PHPUnit will be implemented like so:

The following annotations will not be implemented as attributes:

  • @author string (as alias for @group <string>) because it always only had questionable value
  • @coversDefaultClass ClassName because the workaround it provides is no longer needed as attributes are real syntax

Furthermore, any annotation listed above that is deprecated or not recommended will not be implemented as attributes.

Let us start simple with attributes that do not need parameters:

  • @after will be implemented as PHPUnit\Framework\Attributes\After (only allowed on methods; @after was allowed on classes but did not have an effect there)
  • @afterClass will be implemented as PHPUnit\Framework\Attributes\AfterClass (only allowed on methods; @afterClass was allowed on classes but did not have an effect there)
  • @before will be implemented as PHPUnit\Framework\Attributes\Before (only allowed on methods; @before was allowed on classes but did not have an effect there)
  • @beforeClass will be implemented as PHPUnit\Framework\Attributes\BeforeClass (only allowed on methods; @beforeClass was allowed on classes but did not have an effect there)
  • @codeCoverageIgnore will be implemented as PHPUnit\Framework\Attributes\CodeCoverageIgnore (allowed on classes and methods)
  • @coversNothing will be implemented as PHPUnit\Framework\Attributes\CoversNothing (allowed on classes and methods)
  • @doesNotPerformAssertions will be implemented as PHPUnit\Framework\Attributes\DoesNotPerformAssertions (allowed on classes and methods)
  • @runTestsInSeparateProcesses will be implemented as PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses (only allowed on classes; @runTestsInSeparateProcesses was allowed on methods but did not have an effect there)
  • @runInSeparateProcess will be implemented as PHPUnit\Framework\Attributes\RunInSeparateProcess (only allowed on methods; @runInSeparateProcess was allowed on classes but did not have an effect there)
  • @test will be implemented as PHPUnit\Framework\Attributes\Test (only allowed on methods; @test was allowed on classes but did not have an effect there)
  • @small will be implemented as PHPUnit\Framework\Attributes\Small (only allowed on classes; @small was allowed on methods but it does not make sense to mix tests of different sizes in a test case class)
  • @medium will be implemented as PHPUnit\Framework\Attributes\Medium (only allowed on classes; @medium was allowed on methods but it does not make sense to mix tests of different sizes in a test case class)
  • @large will be implemented as PHPUnit\Framework\Attributes\Large (only allowed on classes; @large was allowed on methods but it does not make sense to mix tests of different sizes in a test case class)
  • @preCondition will be implemented as PHPUnit\Framework\Attributes\PreCondition (only allowed on methods; @preCondition was allowed on classes but did not have an effect there)
  • @postCondition will be implemented as PHPUnit\Framework\Attributes\PostCondition (only allowed on methods; @postCondition was allowed on classes but did not have an effect there)

Here is an example:

<?php declare(strict_types=1);
namespace example;

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\Small;

#[Small]
final class FooTest extends TestCase
{
    // ...
}

And now for the attributes that need parameters:

  • @backupGlobals enabled will be implemented as PHPUnit\Framework\Attributes\BackupGlobals(true) (allowed on classes and methods)
  • @backupGlobals disabled will be implemented as PHPUnit\Framework\Attributes\BackupGlobals(false) (allowed on classes and methods)
  • @backupStaticAttributes enabled will be implemented as PHPUnit\Framework\Attributes\BackupStaticProperties(true) (allowed on classes and methods)
  • @backupStaticAttributes disabled will be implemented as PHPUnit\Framework\Attributes\BackupStaticProperties(false) (allowed on classes and methods)
  • @covers ClassName will be implemented as PHPUnit\Framework\Attributes\CoversClass(string $className) (only allowed on classes; @covers was allowed on methods but it does not make sense to mix different coverage targets in a test case class)
  • @covers ::functionName will be implemented as PHPUnit\Framework\Attributes\CoversFunction(string $functionName) (only allowed on classes; @covers was allowed on methods but it does not make sense to mix different coverage targets in a test case class)
  • @dataProvider methodName will be implemented as PHPUnit\Framework\Attributes\DataProvider(string $methodName) (only allowed on methods; @dataProvider was allowed on classes but did not have an effect there)
  • @dataProvider ClassName::methodName will be implemented as PHPUnit\Framework\Attributes\DataProviderExternal(string $className, string $methodName) (only allowed on methods; @dataProvider was allowed on classes but did not have an effect there)
  • @depends methodName will be implemented as PHPUnit\Framework\Attributes\Depends(string $methodName) (allowed on methods)
  • @depends clone methodName will be implemented as PHPUnit\Framework\Attributes\DependsUsingDeepClone(string $methodName) (allowed on methods)
  • @depends shallowClone methodName will be implemented as PHPUnit\Framework\Attributes\DependsUsingShallowClone(string $methodName) (allowed on methods)
  • @depends ClassName::methodName will be implemented as PHPUnit\Framework\Attributes\DependsExternal(string $className, string $methodName) (allowed on methods)
  • @depends clone ClassName::methodName will be implemented as PHPUnit\Framework\Attributes\DependsExternalUsingDeepClone(string $className, string $methodName) (allowed on methods)
  • @depends shallowClone ClassName::methodName will be implemented as PHPUnit\Framework\Attributes\DependsExternalUsingShallowClone(string $className, string $methodName) (allowed on methods)
  • @depends ClassName::class will be implemented as PHPUnit\Framework\Attributes\DependsOnClass(string $className) (allowed on methods)
  • @depends clone ClassName::class will be implemented as PHPUnit\Framework\Attributes\DependsOnClassUsingDeepClone(string $className) (allowed on methods)
  • @depends shallowClone ClassName::class will be implemented as PHPUnit\Framework\Attributes\DependsOnClassUsingShallowClone(string $className) (allowed on methods)
  • @group string will be implemented as PHPUnit\Framework\Attributes\Group(string) (allowed on classes and methods)
  • @preserveGlobalState enabled will be implemented as PHPUnit\Framework\Attributes\PreserveGlobalState(true) (allowed on classes and methods)
  • @preserveGlobalState disabled will be implemented as PHPUnit\Framework\Attributes\PreserveGlobalState(false) (allowed on classes and methods)
  • @requires PHP <version requirement> will be implemented as PHPUnit\Framework\Attributes\RequiresPhp(string $versionRequirement) (allowed on classes and methods)
  • @requires extension <extension> <operator> <version requirement> will be implemented as PHPUnit\Framework\Attributes\RequiresPhpExtension(string $extension, ?string $versionRequirement = null) (allowed on classes and methods)
  • @requires function <function> will be implemented as PHPUnit\Framework\Attributes\RequiresFunction(string $function) (allowed on classes and methods)
  • @requires function<class>::<method> will be implemented as PHPUnit\Framework\Attributes\RequiresMethod(string $className, string $methodName) (allowed on classes and methods)
  • @requires PHPUnit <version requirement> will be implemented as PHPUnit\Framework\Attributes\RequiresPhpunit(string $versionRequirement) (allowed on classes and methods)
  • @requires OS <os> will be implemented as PHPUnit\Framework\Attributes\RequiresOperatingSystem(string $regularExpression) (allowed on classes and methods)
  • @requires OSFAMILY <family> will be implemented as PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily(string $operatingSystemFamily) (allowed on classes and methods)
  • @requires setting <setting> <value> will be implemented as PHPUnit\Framework\Attributes\RequiresSetting(string $setting, string $value) (allowed on classes and methods)
  • @testdox string will be implemented as PHPUnit\Framework\Attributes\TestDox(string) (allowed on classes and methods)
  • @testWith string will be implemented as PHPUnit\Framework\Attributes\TestWith(array) (only allowed on methods; @testWith was allowed on classes but did not have an effect there)
  • @ticket string will be implemented as PHPUnit\Framework\Attributes\Ticket(string) (allowed on classes and methods)
  • @uses ClassName will be implemented as PHPUnit\Framework\Attributes\UsesClass(string) (only allowed on classes; @uses was allowed on methods but it does not make sense to mix different coverage targets in a test case class)
  • @uses ::functionName will be implemented as PHPUnit\Framework\Attributes\UsesFunction(string) (only allowed on classes; @uses was allowed on methods but it does not make sense to mix different coverage targets in a test case class)

Here is an example:

<?php declare(strict_types=1);
namespace example;

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;

#[CoversClass(Foo::class)]
final class FooTest extends TestCase
{
    // ...
}
@sebastianbergmann sebastianbergmann added the type/enhancement A new idea that should be implemented label Oct 30, 2020
@sebastianbergmann sebastianbergmann added this to the PHPUnit 9.5 milestone Oct 30, 2020
@sebastianbergmann sebastianbergmann self-assigned this Oct 30, 2020
sebastianbergmann added a commit that referenced this issue Nov 16, 2020
@sebastianbergmann sebastianbergmann pinned this issue Nov 30, 2020
@sebastianbergmann sebastianbergmann unpinned this issue Nov 30, 2020
sebastianbergmann added a commit that referenced this issue Dec 5, 2020
sebastianbergmann added a commit that referenced this issue Dec 21, 2020
sebastianbergmann added a commit that referenced this issue Dec 21, 2020
sebastianbergmann added a commit that referenced this issue Dec 22, 2020
sebastianbergmann added a commit that referenced this issue Dec 22, 2020
sebastianbergmann added a commit that referenced this issue Dec 26, 2020
sebastianbergmann added a commit that referenced this issue Dec 26, 2020
sebastianbergmann added a commit that referenced this issue Dec 28, 2020
sebastianbergmann added a commit that referenced this issue Dec 30, 2020
sebastianbergmann added a commit that referenced this issue Jan 1, 2021
sebastianbergmann added a commit that referenced this issue Jan 2, 2021
sebastianbergmann added a commit that referenced this issue Jan 3, 2021
sebastianbergmann added a commit that referenced this issue Jan 22, 2021
sebastianbergmann added a commit that referenced this issue Jan 23, 2021
sebastianbergmann added a commit that referenced this issue Jan 23, 2021
sebastianbergmann added a commit that referenced this issue Jan 24, 2021
sebastianbergmann added a commit that referenced this issue Feb 6, 2021
sebastianbergmann added a commit that referenced this issue Mar 28, 2021
sebastianbergmann added a commit that referenced this issue Apr 20, 2021
sebastianbergmann added a commit that referenced this issue Apr 24, 2021
brettmc added a commit to brettmc/phpunit-global-state that referenced this issue May 2, 2024
PHPUnit 11 emits a deprecation warning when using annotations (@after), and they will not
work in PHPUnit 12.
Changing this means that the "after" functionality will not work in phpunit versions < 10,
but it also should not cause an error. Users directly calling "restoreEnvironmentVariables()"
would be fine, I think. See sebastianbergmann/phpunit#4502
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/enhancement A new idea that should be implemented
Projects
None yet
Development

No branches or pull requests

1 participant