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