开始写新的测试用例类时,可能想从写下空测试方法开始,比如:
public function testSomething() { }
以此来跟踪需要编写的测试。空测试的问题是 PHPUnit 框架会将它们解读为成功。这种错误解读导致错误报告变得毫无用处——无法分辨出测试是真的成功了还是根本就未编写实现。在未实现的测试中调用 $this->fail()
同样没啥帮助,因为测试将被解读为失败。这和将未实现的测试解读为成功是一样的错误。
假如把成功的测试视为绿灯、测试失败视为红灯,那么还额外需要黄灯来将测试标记为不完整或尚未实现。PHPUnit_Framework_IncompleteTest
是一个标记接口,用于将异常(由测试方法抛出)标记为测试不完整或目前尚未实现而导致的结果。PHPUnit_Framework_IncompleteTestError
是这个界面的标准实现。
例 7.1 展示了一个测试用例类 SampleTest
,它有一个测试方法 testSomething()
。通过在测试方法中调用便捷方法 markTestIncomplete()
(会自动抛出一个 PHPUnit_Framework_IncompleteTestError
异常)将这个测试标记为不完整。
例 7.1: 将测试标记为不完整
<?php class SampleTest extends PHPUnit_Framework_TestCase { public function testSomething() { // 可选:如果愿意,在这里随便测试点什么。 $this->assertTrue(TRUE, '这应该已经是能正常工作的。'); // 在这里停止,并将此测试标记为不完整。 $this->markTestIncomplete( '此测试目前尚未实现。' ); } } ?>
在 PHPUnit 命令行测试执行器的输出中,不完整的测试记为 I
,如下例所示:
phpunit --verbose SampleTest
PHPUnit 4.2.0 by Sebastian Bergmann.
I
Time: 0 seconds, Memory: 3.95Mb
There was 1 incomplete test:
1) SampleTest::testSomething
This test has not been implemented yet.
/home/sb/SampleTest.php:12
OK, but incomplete or skipped tests!
Tests: 1, Assertions: 1, Incomplete: 1.
表 7.1 列举了用于将测试标记为不完整的 API。
表 7.1. 用于不完整的测试的 API
方法 | 含义 |
---|---|
void markTestIncomplete() | 将当前测试标记为不完整。 |
void markTestIncomplete(string $message) | 将当前测试标记为不完整,并用 $message 作为说明信息。 |
并非所有测试都能在任何环境中运行。比如说,考虑这样一种情况:一个数据库抽象层,针对其所支持的各种数据库系统有多个不同的驱动程序。针对 MySQL 驱动程序的测试当然只在 MySQL 服务器可用才运行。
例 7.2 展示了一个测试用例类 DatabaseTest
,它有一个测试方法 testConnection()
。在测试用例类的 setUp()
模板方法中,检查了 MySQLi 扩展是否可用,并且在扩展不可用时用 markTestSkipped()
方法来跳过此测试。
例 7.2: 跳过某个测试
<?php class DatabaseTest extends PHPUnit_Framework_TestCase { protected function setUp() { if (!extension_loaded('mysqli')) { $this->markTestSkipped( 'MySQLi 扩展不可用。' ); } } public function testConnection() { // ... } } ?>
在 PHPUnit 命令行测试执行器的输出中,跳过的测试记为 S
,如下例所示:
phpunit --verbose DatabaseTest
PHPUnit 4.2.0 by Sebastian Bergmann.
S
Time: 0 seconds, Memory: 3.95Mb
There was 1 skipped test:
1) DatabaseTest::testConnection
The MySQLi extension is not available.
/home/sb/DatabaseTest.php:9
OK, but incomplete or skipped tests!
Tests: 1, Assertions: 0, Skipped: 1.
表 7.2 列举了用于跳过测试的 API。
表 7.2. 用于跳过测试的 API
方法 | 含义 |
---|---|
void markTestSkipped() | 将当前测试标记为跳过。 |
void markTestSkipped(string $message) | 将当前测试标记为不完整,并用 $message 作为说明信息。 |
除了上述方法,还可以用 @requires
标注来表达测试用例的一些常见前提条件。
表 7.3. 可能的 @requires 用法
类型 | 可能的值 | 范例 | 其他范例 |
---|---|---|---|
PHP | 任何 PHP 版本标识符 | @requires PHP 5.3.3 | @requires PHP 5.4-dev |
PHPUnit | 任何 PHPUnit 版本标识符 | @requires PHPUnit 3.6.3 | @requires PHPUnit 4.2 |
OS | 用来对 PHP_OS 进行匹配的正则表达式 | @requires OS Linux | @requires OS WIN32|WINNT |
function | 任何有效的 function_exists 参数 | @requires function imap_open | @requires function ReflectionMethod::setAccessible |
extension | 任何扩展名称 | @requires extension mysqli | @requires extension curl |
例 7.3: 用 @requires 来跳过测试
<?php /** * @requires extension mysqli */ class DatabaseTest extends PHPUnit_Framework_TestCase { /** * @requires PHP 5.3 */ public function testConnection() { // 测试要求有 mysqli 扩展,并且要求 PHP >= 5.3 } // ... 所有其他需要 mysqli 扩展的测试 } ?>
如果在特定版本的 PHP 下使用了某种无法编译的语法,请在 XML 配置信息中查找包含在 “测试套件”一节 中的关于版本依赖的信息。