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
{
// ...
}
PHPUnit currently supports the following annotations in special PHP comments ("DocBlocks", "doc-comments"):
@after@afterClass@backupGlobals enabledand@backupGlobals disabled@backupStaticAttributes enabledand@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 enabledand@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 tofunction_exists())@requires function <class>::<method>(where<class>and<method>are passed tomethod_exists())@requires setting <setting> <value>(where<setting>is a configuration setting that can be queried withini_set()for comparison with<value>)@requires OS <os>(where<os>is a regular expression that is applied toPHP_OS)@requires OSFAMILY <family>(where<family>is compared toPHP_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
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 ClassNamebecause the workaround it provides is no longer needed as attributes are real syntaxFurthermore, 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:
@afterwill be implemented asPHPUnit\Framework\Attributes\After(only allowed on methods;@afterwas allowed on classes but did not have an effect there)@afterClasswill be implemented asPHPUnit\Framework\Attributes\AfterClass(only allowed on methods;@afterClasswas allowed on classes but did not have an effect there)@beforewill be implemented asPHPUnit\Framework\Attributes\Before(only allowed on methods;@beforewas allowed on classes but did not have an effect there)@beforeClasswill be implemented asPHPUnit\Framework\Attributes\BeforeClass(only allowed on methods;@beforeClasswas allowed on classes but did not have an effect there)@codeCoverageIgnorewill be implemented asPHPUnit\Framework\Attributes\CodeCoverageIgnore(allowed on classes and methods)@coversNothingwill be implemented asPHPUnit\Framework\Attributes\CoversNothing(allowed on classes and methods)@doesNotPerformAssertionswill be implemented asPHPUnit\Framework\Attributes\DoesNotPerformAssertions(allowed on classes and methods)@runTestsInSeparateProcesseswill be implemented asPHPUnit\Framework\Attributes\RunTestsInSeparateProcesses(only allowed on classes;@runTestsInSeparateProcesseswas allowed on methods but did not have an effect there)@runInSeparateProcesswill be implemented asPHPUnit\Framework\Attributes\RunInSeparateProcess(only allowed on methods;@runInSeparateProcesswas allowed on classes but did not have an effect there)@testwill be implemented asPHPUnit\Framework\Attributes\Test(only allowed on methods;@testwas allowed on classes but did not have an effect there)@smallwill be implemented asPHPUnit\Framework\Attributes\Small(only allowed on classes;@smallwas allowed on methods but it does not make sense to mix tests of different sizes in a test case class)@mediumwill be implemented asPHPUnit\Framework\Attributes\Medium(only allowed on classes;@mediumwas allowed on methods but it does not make sense to mix tests of different sizes in a test case class)@largewill be implemented asPHPUnit\Framework\Attributes\Large(only allowed on classes;@largewas allowed on methods but it does not make sense to mix tests of different sizes in a test case class)@preConditionwill be implemented asPHPUnit\Framework\Attributes\PreCondition(only allowed on methods;@preConditionwas allowed on classes but did not have an effect there)@postConditionwill be implemented asPHPUnit\Framework\Attributes\PostCondition(only allowed on methods;@postConditionwas allowed on classes but did not have an effect there)Here is an example:
And now for the attributes that need parameters:
@backupGlobals enabledwill be implemented asPHPUnit\Framework\Attributes\BackupGlobals(true)(allowed on classes and methods)@backupGlobals disabledwill be implemented asPHPUnit\Framework\Attributes\BackupGlobals(false)(allowed on classes and methods)@backupStaticAttributes enabledwill be implemented asPHPUnit\Framework\Attributes\BackupStaticProperties(true)(allowed on classes and methods)@backupStaticAttributes disabledwill be implemented asPHPUnit\Framework\Attributes\BackupStaticProperties(false)(allowed on classes and methods)@covers ClassNamewill be implemented asPHPUnit\Framework\Attributes\CoversClass(string $className)(only allowed on classes;@coverswas allowed on methods but it does not make sense to mix different coverage targets in a test case class)@covers ::functionNamewill be implemented asPHPUnit\Framework\Attributes\CoversFunction(string $functionName)(only allowed on classes;@coverswas allowed on methods but it does not make sense to mix different coverage targets in a test case class)@dataProvider methodNamewill be implemented asPHPUnit\Framework\Attributes\DataProvider(string $methodName)(only allowed on methods;@dataProviderwas allowed on classes but did not have an effect there)@dataProvider ClassName::methodNamewill be implemented asPHPUnit\Framework\Attributes\DataProviderExternal(string $className, string $methodName)(only allowed on methods;@dataProviderwas allowed on classes but did not have an effect there)@depends methodNamewill be implemented asPHPUnit\Framework\Attributes\Depends(string $methodName)(allowed on methods)@depends clone methodNamewill be implemented asPHPUnit\Framework\Attributes\DependsUsingDeepClone(string $methodName)(allowed on methods)@depends shallowClone methodNamewill be implemented asPHPUnit\Framework\Attributes\DependsUsingShallowClone(string $methodName)(allowed on methods)@depends ClassName::methodNamewill be implemented asPHPUnit\Framework\Attributes\DependsExternal(string $className, string $methodName)(allowed on methods)@depends clone ClassName::methodNamewill be implemented asPHPUnit\Framework\Attributes\DependsExternalUsingDeepClone(string $className, string $methodName)(allowed on methods)@depends shallowClone ClassName::methodNamewill be implemented asPHPUnit\Framework\Attributes\DependsExternalUsingShallowClone(string $className, string $methodName)(allowed on methods)@depends ClassName::classwill be implemented asPHPUnit\Framework\Attributes\DependsOnClass(string $className)(allowed on methods)@depends clone ClassName::classwill be implemented asPHPUnit\Framework\Attributes\DependsOnClassUsingDeepClone(string $className)(allowed on methods)@depends shallowClone ClassName::classwill be implemented asPHPUnit\Framework\Attributes\DependsOnClassUsingShallowClone(string $className)(allowed on methods)@group stringwill be implemented asPHPUnit\Framework\Attributes\Group(string)(allowed on classes and methods)@preserveGlobalState enabledwill be implemented asPHPUnit\Framework\Attributes\PreserveGlobalState(true)(allowed on classes and methods)@preserveGlobalState disabledwill be implemented asPHPUnit\Framework\Attributes\PreserveGlobalState(false)(allowed on classes and methods)@requires PHP <version requirement>will be implemented asPHPUnit\Framework\Attributes\RequiresPhp(string $versionRequirement)(allowed on classes and methods)@requires extension <extension> <operator> <version requirement>will be implemented asPHPUnit\Framework\Attributes\RequiresPhpExtension(string $extension, ?string $versionRequirement = null)(allowed on classes and methods)@requires function <function>will be implemented asPHPUnit\Framework\Attributes\RequiresFunction(string $function)(allowed on classes and methods)@requires function<class>::<method>will be implemented asPHPUnit\Framework\Attributes\RequiresMethod(string $className, string $methodName)(allowed on classes and methods)@requires PHPUnit <version requirement>will be implemented asPHPUnit\Framework\Attributes\RequiresPhpunit(string $versionRequirement)(allowed on classes and methods)@requires OS <os>will be implemented asPHPUnit\Framework\Attributes\RequiresOperatingSystem(string $regularExpression)(allowed on classes and methods)@requires OSFAMILY <family>will be implemented asPHPUnit\Framework\Attributes\RequiresOperatingSystemFamily(string $operatingSystemFamily)(allowed on classes and methods)@requires setting <setting> <value>will be implemented asPHPUnit\Framework\Attributes\RequiresSetting(string $setting, string $value)(allowed on classes and methods)@testdox stringwill be implemented asPHPUnit\Framework\Attributes\TestDox(string)(allowed on classes and methods)@testWith stringwill be implemented asPHPUnit\Framework\Attributes\TestWith(array)(only allowed on methods;@testWithwas allowed on classes but did not have an effect there)@ticket stringwill be implemented asPHPUnit\Framework\Attributes\Ticket(string)(allowed on classes and methods)@uses ClassNamewill be implemented asPHPUnit\Framework\Attributes\UsesClass(string)(only allowed on classes;@useswas allowed on methods but it does not make sense to mix different coverage targets in a test case class)@uses ::functionNamewill be implemented asPHPUnit\Framework\Attributes\UsesFunction(string)(only allowed on classes;@useswas allowed on methods but it does not make sense to mix different coverage targets in a test case class)Here is an example: