相依的測試
在傳統的單元測試觀念中,測試方法應該是要獨立的。但後來也因為軟體的複雜變化,我們不再強調單元測試的獨立性,而是有系統地依照一連串的動作來進行測試。
分離測試方法
我們不太可能在一個測試方法裡把所有想測試的東西測完,一般來說會針對被測試類別的每個方法各寫一個測試。所以接著將之前的程式碼重寫如下:
<?php
/* tests/CartTest.php */
require __DIR__ . '/../Cart.php';
class CartTest extends PHPUnit_Framework_TestCase
{
public function testUpdateQuantitiesAndGetTotal()
{
$cart = new Cart();
// Test 1
$quantities = [
1, 0, 0, 0, 0, 0,
];
$cart->updateQuantities($quantities);
$this->assertEquals(199, $cart->getTotal());
// Test 2
$quantities = [
1, 0, 0, 2, 0, 0,
];
$cart->updateQuantities($quantities);
$this->assertEquals(797, $cart->getTotal());
}
public function testGetProducts()
{
$cart = new Cart();
$products = $cart->getProducts();
$this->assertEquals(6, count($products));
$this->assertEquals(2, $products[3]['quantity']);
}
}
主要做了以下變動:
updateQuantities
和getTotal
方法放在一起測試。getProducts
方法獨立測試。- 測試方法名稱改為跟被測試方法相關連,例如
testUpdateQuantitiesAndGetTotal
與testGetTotal
接著重新測試執行測試:
C:\project> phpunit tests/CartTest
PHPUnit 4.2.5 by Sebastian Bergmann.
.F
Time: 33 ms, Memory: 3.00Mb
There was 1 failure:
1) CartTest::testGetProducts
Failed asserting that 0 matches expected 2.
C:\project\tests\CartTest.php:32
FAILURES!
Tests: 2, Assertions: 4, Failures: 1.
這裡可以看到測試失敗了,主要是因為每個測試都是獨立的,而先前我們對第四個商品數量的斷言就錯了。
$this->assertEquals(2, $products[3]['quantity']); // 第四個商品數量應為 0
這時候我們需要讓測試方法相依於另一個測試方法。
定義測試相依性
當測試方法之間有相依順序時, PHPUnit 提供 @depends
這個註記來定義測試方法之間相依關係;而被相依的測試需要回傳值來提供給下一個測試,下一個測試就可以用參數來接收這個回傳值。
因此上述的程式可以改成:
<?php
/* tests/CartTest.php */
require __DIR__ . '/../Cart.php';
class CartTest extends PHPUnit_Framework_TestCase
{
public function testUpdateQuantitiesAndGetTotal()
{
$cart = new Cart();
// ... 略 ...
return $cart;
}
/**
* @depends testUpdateQuantitiesAndGetTotal
*/
public function testGetProducts($cart)
{
$products = $cart->getProducts();
$this->assertEquals(6, count($products));
$this->assertEquals(2, $products[3]['quantity']);
}
}
首先在
testUpdateQuantitiesAndGetTotal
方法中,把最後的$cart
物件回傳。而在
testGetProducts
方法的 DocBlock 上定義:@depends testUpdateQuantitiesAndGetTotal
讓
testGetProducts
方法可以接收testUpdateQuantitiesAndGetTotal
方法的回傳值。假設測試
testGetProducts
方法相依其他多個測試方法,那麼這些方法的回傳值就會變成testGetProducts
的參數;而參數順序就是依照 DocBlock 中@depends
定義的順序。
官方手冊參考
練習
思考單元測試中,獨立測試是重要的?
思考為什麼測試方法之間需要有相依性?