開始寫新的測試用例類時(shí),可能想從寫下空測試方法開始,比如:
public function testSomething(): void
{
}
以此來跟蹤需要編寫的測試??諟y試的問題是 PHPUnit 框架會(huì)將它們解讀為成功。這種錯(cuò)誤解讀導(dǎo)致錯(cuò)誤報(bào)告變得毫無用處——無法分辨出測試是真的成功了還是根本就未編寫實(shí)現(xiàn)。在未實(shí)現(xiàn)的測試中調(diào)用 ?$this->fail()
? 同樣沒啥幫助,因?yàn)闇y試將被解讀為失敗。這和將未實(shí)現(xiàn)的測試解讀為成功是一樣的錯(cuò)誤。
假如把成功的測試視為綠燈、測試失敗視為紅燈,那么還額外需要黃燈來將測試標(biāo)記為未完成或尚未實(shí)現(xiàn)。?PHPUnit\Framework\IncompleteTest
? 是一個(gè)標(biāo)記接口,用于將測試方法拋出的異常標(biāo)記為測試未完成或目前尚未實(shí)現(xiàn)而導(dǎo)致的結(jié)果。?PHPUnit\Framework\IncompleteTestError
? 是這個(gè)接口的標(biāo)準(zhǔn)實(shí)現(xiàn)。
示例 7.1 展示了一個(gè)測試用例類 ?SampleTest
?,它有一個(gè)測試方法 ?testSomething()
?。通過在測試方法中調(diào)用便捷方法 ?markTestIncomplete()
(會(huì)自動(dòng)拋出一個(gè) ?PHPUnit\Framework\IncompleteTestError
? 異常)將這個(gè)測試標(biāo)記為未完成。
示例 7.1 將測試標(biāo)記為不完整
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class SampleTest extends TestCase
{
public function testSomething(): void
{
// 可選:如果愿意,在這里隨便測試點(diǎn)什么。
$this->assertTrue(true, 'This should already work.');
// 在這里停止,并將此測試標(biāo)記為未完成。
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
}
在 PHPUnit 命令行測試執(zhí)行器的輸出中,未完成的測試記為 ?I
?,如下例所示:
$ phpunit --verbose SampleTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.
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 列舉了用于將測試標(biāo)記為未完成的 API。
表格 7.1 用于不完整的測試的 API
方法 | 含義 |
void markTestIncomplete() ? |
將當(dāng)前測試標(biāo)記為未完成。 |
void markTestIncomplete(string $message) ? |
將當(dāng)前測試標(biāo)記為未完成。并用 ?$message ? 作為說明信息。 |
并非所有測試都能在任何環(huán)境中運(yùn)行。比如說,考慮這樣一種情況:一個(gè)數(shù)據(jù)庫抽象層,針對其所支持的各種數(shù)據(jù)庫系統(tǒng)有多個(gè)不同的驅(qū)動(dòng)程序。針對 MySQL 驅(qū)動(dòng)程序的測試只在 MySQL 服務(wù)器可用才能運(yùn)行。
示例 7.2 展示了一個(gè)測試用例類 ?DatabaseTest
?,它有一個(gè)測試方法 ?testConnection()
?。在測試用例類的 ?setUp()
? 模板方法中,檢查了 MySQLi 擴(kuò)展是否可用,并且在擴(kuò)展不可用時(shí)用 ?markTestSkipped()
? 方法來跳過此測試。
示例 7.2 跳過測試
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class DatabaseTest extends TestCase
{
protected function setUp(): void
{
if (!extension_loaded('mysqli')) {
$this->markTestSkipped(
'The MySQLi extension is not available.'
);
}
}
public function testConnection(): void
{
// ...
}
}
在 PHPUnit 命令行測試執(zhí)行器的輸出中,被跳過的測試記為 ?S
?,如下例所示:
$ phpunit --verbose DatabaseTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.
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() ? |
將當(dāng)前測試標(biāo)記為已跳過。 |
?void markTestSkipped(string $message) ? |
將當(dāng)前測試標(biāo)記為已跳過,并用 ?$message ? 作為說明信息。 |
除了上述方法,還可以用 ?@requires
? 標(biāo)注來表達(dá)測試用例的一些常見前提條件。
表格 7.3 可能的 @requires 用法
類型 | 可能值 | 示例 | 其他示例 |
PHP | 任意PHP版本號以及可選的運(yùn)算符 | @requires PHP 7.1.20 | @requires PHP >= 7.2 |
PHPUnit | 任意PHPUnit版本號以及可選的運(yùn)算符 | @requires PHPUnit 7.3.1 | @requires PHPUnit < 8 |
OS | 與 PHP_OS 匹配的正則表達(dá)式 | @requires OS Linux | @requires OS WIN32|WINNT |
OSFAMILY | 任意 OS family | @requires OSFAMILY Solaris | @requires OSFAMILY Windows |
function | 任意 function_exists 的有效參數(shù) | @requires function imap_open | @requires function ReflectionMethod::setAccessible |
extension | 任意擴(kuò)展名以及可選的版本號和可選的運(yùn)算符 | @requires extension mysqli | @requires extension redis >= 2.2.0 |
PHP、PHPUnit 和擴(kuò)展的版本約束支持以下運(yùn)算符:?<
?、?<=
?、?>
?、?>=
?、?=
?、?==
?、?!=
?、?<>
?。
版本是用 PHP 的 version_compare 函數(shù)進(jìn)行比較的。除了其他事情之外,這意味著 ?=
? 和 ?==
? 運(yùn)算符只能用于完整的 ?X.Y.Z
? 版本號,只用 ?X.Y
? 是不行的。
示例 7.3 用 @requires 跳過測試
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
/**
* @requires extension mysqli
*/
final class DatabaseTest extends TestCase
{
/**
* @requires PHP >= 5.3
*/
public function testConnection(): void
{
// 測試需要 mysqli 擴(kuò)展,并且要求 PHP >= 5.3
}
// ... 其他需要 mysqli 擴(kuò)展的測試
}
更多建議: