开始写新的测试用例类时,可能想从写下空测试方法开始,比如:
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 配置信息中查找包含在 “测试套件”一节 中的关于版本依赖的信息。