示例 2.1 展示了如何用 PHPUnit 編寫測試來對 PHP 數(shù)組操作進行測試。此示例介紹了用 PHPUnit 編寫測試的基本慣例與步驟:
Class
?的測試寫在類 ?ClassTest
?中。ClassTest
?(通常)繼承自 ?PHPUnit\Framework\TestCase
?。test*
? 的公用方法。也可以在方法的文檔注釋塊(docblock)中使用 ?@test
? 標注將其標記為測試方法。assertSame()
這樣的斷言方法用來對實際值與預(yù)期值的匹配做出斷言。示例 2.1 用 PHPUnit 測試數(shù)組操作
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StackTest extends TestCase
{
public function testPushAndPop(): void
{
$stack = [];
$this->assertSame(0, count($stack));
array_push($stack, 'foo');
$this->assertSame('foo', $stack[count($stack)-1]);
$this->assertSame(1, count($stack));
$this->assertSame('foo', array_pop($stack));
$this->assertSame(0, count($stack));
}
}
當你想把一些東西寫到 ?print
?語句或者調(diào)試表達式中時,別這么做,改為將其寫成測試。
單元測試主要是作為一種良好實踐來編寫的,它能幫助開發(fā)人員識別并修復(fù) bug、重構(gòu)代碼,還可以看作被測軟件單元的文檔。要實現(xiàn)這些好處,理想的單元測試應(yīng)當覆蓋程序中所有可能的路徑。一個單元測試通常覆蓋一個函數(shù)或方法中的一個特定路徑。但是,測試方法不一定是封裝良好的獨立實體。測試方法之間經(jīng)常有隱含的依賴關(guān)系暗藏在測試的實現(xiàn)方案中。
PHPUnit支持對測試方法之間的顯式依賴關(guān)系進行聲明。這種依賴關(guān)系并不是定義在測試方法的執(zhí)行順序中,而是允許生產(chǎn)者(producer)返回一個測試基境(fixture)的實例,并將此實例傳遞給依賴于它的消費者(consumer)們。
示例 2.2 展示了如何用 ?@depends
? 標注來表示測試方法之間的依賴關(guān)系。
示例 2.2 用 ?@depends
? 標注來表示依賴關(guān)系
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StackTest extends TestCase
{
public function testEmpty(): array
{
$stack = [];
$this->assertEmpty($stack);
return $stack;
}
/**
* @depends testEmpty
*/
public function testPush(array $stack): array
{
array_push($stack, 'foo');
$this->assertSame('foo', $stack[count($stack)-1]);
$this->assertNotEmpty($stack);
return $stack;
}
/**
* @depends testPush
*/
public function testPop(array $stack): void
{
$this->assertSame('foo', array_pop($stack));
$this->assertEmpty($stack);
}
}
在上例中,第一個測試?testEmpty()
? 創(chuàng)建了一個新數(shù)組,并斷言其為空。隨后,此測試將此基境作為結(jié)果返回。第二個測試 ?testPush()
? 依賴于 ?testEmpty()
?,并將所依賴的測試之結(jié)果作為參數(shù)傳入。最后,?testPop()
? 依賴于 ?testPush()
?。
注解:
默認情況下,生產(chǎn)者所產(chǎn)生的返回值將原樣傳遞給相應(yīng)的消費者。這意味著,如果生產(chǎn)者返回的是一個對象,那么傳遞給消費者的將是指向此對象的引用。但同樣也可以(a)通過 ?@depends clone
? 來傳遞指向深拷貝對象的引用,或(b)通過 ?@depends shallowClone
? 來傳遞指向正常淺克隆對象(基于 PHP 關(guān)鍵字 ?clone
?)的引用。
為了定位缺陷,我們希望把注意力集中于相關(guān)的失敗測試上。這就是為什么當某個測試所依賴的測試失敗時,PHPUnit 會跳過這個測試。利用測試之間的依賴關(guān)系可以改進缺陷定位,如示例 2.3 所示。
示例 2.3 利用測試之間的依賴關(guān)系
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class DependencyFailureTest extends TestCase
{
public function testOne(): void
{
$this->assertTrue(false);
}
/**
* @depends testOne
*/
public function testTwo(): void
{
}
}
$ phpunit --verbose DependencyFailureTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.
FS
Time: 0 seconds, Memory: 5.00Mb
There was 1 failure:
1) DependencyFailureTest::testOne
Failed asserting that false is true.
/home/sb/DependencyFailureTest.php:6
There was 1 skipped test:
1) DependencyFailureTest::testTwo
This test depends on "DependencyFailureTest::testOne" to pass.
FAILURES!
Tests: 1, Assertions: 1, Failures: 1, Skipped: 1.
測試可以使用多個 ?@depends
? 標注。PHPUnit 不會更改測試的運行順序,因此你需要自行保證某個測試所依賴的所有測試均出現(xiàn)于這個測試之前。
擁有多個 ?@depends
? 標注的測試,其第一個參數(shù)是第一個生產(chǎn)者提供的基境,第二個參數(shù)是第二個生產(chǎn)者提供的基境,以此類推。參見示例 2.4
示例 2.4 有多個依賴項的測試
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class MultipleDependenciesTest extends TestCase
{
public function testProducerFirst(): string
{
$this->assertTrue(true);
return 'first';
}
public function testProducerSecond(): string
{
$this->assertTrue(true);
return 'second';
}
/**
* @depends testProducerFirst
* @depends testProducerSecond
*/
public function testConsumer(string $a, string $b): void
{
$this->assertSame('first', $a);
$this->assertSame('second', $b);
}
}
$ phpunit --verbose MultipleDependenciesTest
PHPUnit latest.0 by Sebastian Bergmann and contributors.
...
Time: 0 seconds, Memory: 3.25Mb
OK (3 tests, 4 assertions)
更多建議: