Annotations

注释

注释是一种特殊形式的语法元数据,可以添加到某些编程语言的源代码中。虽然 PHP 没有用于注释源代码的专用语言功能,但@annotation arguments在 PHP 社区中已经建立了使用标记块(如文档块)中的标记来注释源代码。在 PHP 文档中,块是反射的:它们可以通过 Reflection API 的getDocComment()函数,类,方法和属性级别的方法访问。诸如 PHPUnit 之类的应用程序在运行时使用这些信息来配置它们的行为。

PHP 中的文档注释必须以开头/**和结尾*/。任何其他解释风格的注释都将被忽略。

本附录显示了 PHPUnit 支持的所有注释类型。

@author

@author注释是为一个别名@group注释(见一节“@group”),并允许筛选基于它们的作者的测试。

@after

@after注释可用于指定应在一个测试用例类每个测试方法之后被调用的方法。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @after */ public function tearDownSomeFixtures() { // ... } /** * @after */ public function tearDownSomeOtherFixtures() { // ... } }

@afterClass

@afterClass注解可以用来指定后在测试类中的所有测试方法已运行到清理共享固定设备时应调用静态方法。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @afterClass */ public static function tearDownSomeSharedFixtures() { // ... } /** * @afterClass */ public static function tearDownSomeOtherSharedFixtures() { // ... } }

@backupGlobals

对于像这样的测试用例类的所有测试,可以完全禁用全局变量的备份和恢复操作

use PHPUnit\Framework\TestCase; /** * @backupGlobals disabled */ class MyTest extends TestCase { // ... }

@backupGlobals注释也可以在该测试方法水平使用。这允许对备份和恢复操作进行精细配置:

use PHPUnit\Framework\TestCase; /** * @backupGlobals disabled */ class MyTest extends TestCase { /** * @backupGlobals enabled */ public function testThatInteractsWithGlobalVariables() { // ... } }

@backupStaticAttributes

@backupStaticAttributes注释可以用来备份所有静态的属性值中的所有声明的类每次测试前和事后恢复它们。它可以用在测试用例类或测试方法级别:

use PHPUnit\Framework\TestCase; /** * @backupStaticAttributes enabled */ class MyTest extends TestCase { /** * @backupStaticAttributes disabled */ public function testThatInteractsWithStaticAttributes() { // ... } }

@backupStaticAttributes 受到 PHP 内部的限制,并且在某些情况下可能会导致意外的静态值持续存在并泄漏到后续测试中。

有关详细信息,请参阅“全局状态”一节。

@before

@before注释可用于指定应在一个测试用例类每个测试方法之前被调用的方法。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @before */ public function setupSomeFixtures() { // ... } /** * @before */ public function setupSomeOtherFixtures() { // ... } }

@beforeClass

@beforeClass注解可以用于指定测试类中的任何测试方法运行设置共享灯具前应称为静态方法。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @beforeClass */ public static function setUpSomeSharedFixtures() { // ... } /** * @beforeClass */ public static function setUpSomeOtherSharedFixtures() { // ... } }

@codeCoverageIgnore*

The `@codeCoverageIgnore`, `@codeCoverageIgnoreStart` and `@codeCoverageIgnoreEnd` annotations can be used to exclude lines of code from the coverage analysis.

有关用法,请参阅“忽略代码块”一节。

@covers

@covers注释可以在测试代码被用于指定该方法(一个或多个)的测试方法要测试:

/** * @covers BankAccount::getBalance */ public function testBalanceIsInitiallyZero() { $this->assertEquals(0, $this->ba->getBalance() }

如果提供,将只考虑指定方法的代码覆盖率信息。

表 B.1显示了@covers注释的语法。

表 B.1用于指定测试涵盖哪些方法的注释

注释描述
@covers ClassName::methodName 指定注释的测试方法覆盖指定的方法。
@covers ClassName 指定注释的测试方法覆盖给定类的所有方法。
@covers ClassName<extended> 指定注释测试方法覆盖给定类及其父类和接口的所有方法。
@covers ClassName::<public> 指定注释测试方法覆盖给定类的所有公共方法。
@covers ClassName::<protected> 指定注释测试方法覆盖给定类的所有受保护方法。
@covers ClassName::<private> 指定注释测试方法覆盖给定类的所有私有方法。
@covers ClassName::<!public> 指定带注释的测试方法覆盖给定类中所有未公开的方法。
@covers ClassName::<!protected> 指定注释的测试方法覆盖给定类中未受保护的所有方法。
@covers ClassName::<!private> 指定带注释的测试方法覆盖给定类的所有非私有方法。
@covers ::functionName 指定注释的测试方法覆盖指定的全局函数。

@coversDefaultClass

@coversDefaultClass注释可以用来指定一个默认的命名空间或类名。这种方式长名称不需要重复每个@covers注释。见例B.1。

示例 B.1:使用@coversDefaultClass 缩短注释

<?php use PHPUnit\Framework\TestCase; /** * @coversDefaultClass \Foo\CoveredClass */ class CoversDefaultClassTest extends TestCase { /** * @covers ::publicMethod */ public function testSomething() { $o = new Foo\CoveredClass; $o->publicMethod( } } ?>

@coversNothing

@coversNothing注释可以在测试代码中使用指定不代码覆盖率信息将被记录为注释测试用例。

这可以用于集成测试。示例见例11.3。

注释可以在类和方法级别上使用,并将覆盖任何@covers标签。

@dataProvider

一个测试方法可以接受任意的参数。这些参数将由数据提供者方法提供(在例2.5中provider())。要使用的数据提供者方法使用@dataProvider注释来指定。

有关更多详细信息,请参阅“数据提供者”部分。

@depends

PHPUnit 支持测试方法之间显式依赖关系的声明。这种依赖关系不定义测试方法执行的顺序,但它们允许生产者返回测试装置的实例,并将其传递给相关消费者。例2.2展示了如何使用@depends注解来表达测试方法之间的依赖关系。

有关更多详细信息,请参阅“测试相关性”部分。

@expectedException

例2.10展示了如何使用@expectedException注解来测试在被测代码中是否引发了一个异常。

有关更多详细信息,请参阅“测试例外”一节。

@expectedExceptionCode

@expectedExceptionCode注释,在用连词@expectedException上从而能够缩小特定异常的抛出异常的错误代码允许作出断言。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @expectedException MyException * @expectedExceptionCode 20 */ public function testExceptionHasErrorcode20() { throw new MyException('Some Message', 20 } }

为了简化测试并减少重复,可以使用快捷方式将类常量指定为@expectedExceptionCode使用“ @expectedExceptionCode ClassName::CONST”语法。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @expectedException MyException * @expectedExceptionCode MyClass::ERRORCODE */ public function testExceptionHasErrorcode20() { throw new MyException('Some Message', 20 } } class MyClass { const ERRORCODE = 20; }

@expectedExceptionMessage

@expectedExceptionMessage注释的工作原理@expectedExceptionCode类似,因为它可以让你做出一个异常的错误消息的断言。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @expectedException MyException * @expectedExceptionMessage Some Message */ public function testExceptionHasRightMessage() { throw new MyException('Some Message', 20 } }

预期的消息可以是异常消息的子字符串。这可以用于仅声明传入的特定名称或参数显示在异常中,并且不会在测试中注意整个异常消息。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @expectedException MyException * @expectedExceptionMessage broken */ public function testExceptionHasRightMessage() { $param = "broken"; throw new MyException('Invalid parameter "'.$param.'".', 20 } }

为了简化测试并减少重复,可以使用快捷方式将类常量指定为@expectedExceptionMessage使用“ @expectedExceptionMessage ClassName::CONST”语法。样本可以在“@expectedExceptionCode”部分找到。

@expectedExceptionMessageRegExp

预期消息也可以使用@expectedExceptionMessageRegExp注释指定为正则表达式。这对于子字符串不足以匹配给定消息的情况很有用。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @expectedException MyException * @expectedExceptionMessageRegExp /Argument \d+ can not be an? \w+/ */ public function testExceptionHasRightMessage() { throw new MyException('Argument 2 can not be an integer' } }

@group

可以使用这样的@group注释将测试标记为属于一个或多个组

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @group specification */ public function testSomething() { } /** * @group regresssion * @group bug2204 */ public function testSomethingElse() { } }

可以使用命令行测试运行器的选项--group--exclude-group选项,或使用 XML 配置文件的相应指令,选择测试进行执行。

@large

@large注释是一个别名@group large

如果PHP_Invoker软件包已安装且启用了严格模式,则如果执行时间超过60秒,则大型测试将失败。该超时可通过XML配置文件中timeoutForLargeTests的属性进行配置。

@medium

@medium注释是@group medium一个别名。中等测试不得依赖于标记为@large的测试。

如果PHP_Invoker安装了软件包并启用了严格模式,则如果执行的时间超过10秒,则中等测试将失败。该超时可通过XML配置文件中timeoutForMediumTests的属性进行配置。

@preserveGlobalState

当一个测试在单独的进程中运行时,PHPUnit 将尝试通过序列化父进程中的所有全局变量并在子进程中反序列化它们来尝试从父进程保留全局状态。如果父进程包含不可序列化的全局变量,这可能会导致问题。为了解决这个问题,你可以阻止 PHPUnit 使用@preserveGlobalState注解保留全局状态。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @runInSeparateProcess * @preserveGlobalState disabled */ public function testInSeparateProcess() { // ... } }

@requires

当常见的前置条件(如PHP版本或已安装的扩展)未得到满足时 ,@requires注释可用于跳过测试。

表7.3 列出了可能性和范例的完整列表

@runTestsInSeparateProcesses

表示测试类中的所有测试应该在单独的 PHP 进程中运行。

use PHPUnit\Framework\TestCase; /** * @runTestsInSeparateProcesses */ class MyTest extends TestCase { // ... }

注意:默认情况下,PHPUnit 将尝试通过序列化父进程中的所有全局变量并在子进程中将其反序列化来从父进程保留全局状态。如果父进程包含不可序列化的全局变量,这可能会导致问题。有关如何解决此问题的信息,请参阅“@preserveGlobalState”部分。

@runInSeparateProcess

表示测试应该在单独的 PHP 进程中运行。

use PHPUnit\Framework\TestCase; class MyTest extends TestCase { /** * @runInSeparateProcess */ public function testInSeparateProcess() { // ... } }

注意:默认情况下,PHPUnit 将尝试通过序列化父进程中的所有全局变量并在子进程中将其反序列化来从父进程保留全局状态。如果父进程包含不可序列化的全局变量,这可能会导致问题。有关如何解决此问题的信息,请参阅“@preserveGlobalState”部分。

@small

@small注释是一个别名@group small。小测试不能取决于标记为@medium@large的测试。

如果PHP_Invoker安装了软件包并启用了严格模式,则如果执行时间超过1秒,则小测试将失败。该超时可通过XML配置文件中的timeoutForSmallTests属性进行配置。

测试需要由已被明确注释@small@medium@large使运行时间限制。

@test

As an alternative to prefixing your test method names with test, you can use the @test annotation in a method's DocBlock to mark it as a test method.

/** * @test */ public function initialBalanceShouldBe0() { $this->assertEquals(0, $this->ba->getBalance() }

@testdox

@ticket

@uses

@uses注释指定将通过测试被执行,但并不意在由测试所覆盖的代码。一个很好的例子是测试代码单元所需的值对象。

/** * @covers BankAccount::deposit * @uses Money */ public function testMoneyCanBeDepositedInAccount() { // ... }

这个注解在严格的覆盖模式下非常有用,在这种模式下,无意识的代码会导致测试失败。有关严格覆盖模式的更多信息,请参阅“无意覆盖代码”一节。