對異常進行測試
對於一些我們能預見的異常行為 (Exception) ,程式都應該要處理;那麼如何確保我們的程式有抓到這些異常呢?測試就可以協助我們做到這件事。
建立異常處理程式
我們的範例中有個問題,那就是沒有檢查數量小於 0 的部份。因此我們要針對這部份加強它。
首先是修改 Cart.php
,加入數量的判斷:
<?php
class Cart
{
// ...
public function updateQuantities($quantities)
{
foreach ($quantities as $key => $qty) {
if (!is_numeric($qty) || (int) $qty < 0) {
throw new CartException("數量不正確,請輸入 0 或 0 以上的整數", 1);
}
// ...
}
// ...
}
// ...
}
class CartException extends Exception
{
}
然後在 index.php
中捕捉它:
<?php
// ...
if ('POST' === $_SERVER['REQUEST_METHOD']) {
try {
$cart->updateQuantities($_POST['quantity']);
$_SESSION['cart'] = serialize($cart);
} catch (CartException $e) {
header('Content-Type: text/plain; charset="utf-8"');
echo $e->getMessage();
exit;
}
header('Location: /');
exit;
}
//...
使用瀏覽器測試,在任一數量輸入框輸入負值後,就會得到錯誤訊息。
但怎麼在測試中測得異常狀況呢?
測試異常
在 PHPUnit 中,可以透過定義 @expectedException
註記來告知這個測試會產生預期的異常。因此,在測試裡我們加入了一個 testUpdateQuantitiesWithException
方法。
<?php
class CartTest extends PHPUnit_Framework_TestCase
{
// ...
/**
* @expectedException CartException
*/
public function testUpdateQuantitiesWithException()
{
$cart = new Cart();
$quantities = [ -1, 0, 0, 0, 0, 0 ];
$cart->updateQuantities($quantities); // 預期會產生一個 Exception
}
// ...
}
@expectedException
後面接一個 Exception 類別名稱,也可以是萬用Exception
類別。如同
catch
敘述,不同的 Exception 類別都需要一個測試方法。如果標註了
@expectedException
,但卻沒有發生異常,那麼就是程式邏輯有 bug 。@expectedExceptionMessage
與@expectedExceptionCode
則分別代表預期的異常訊息與預期的異常代號。
另外也可以在測試中以 $this->setExpectedException('ExceptionClassName');
來設定程式預期會丟出的異常,例如:
<?php
class CartTest extends PHPUnit_Framework_TestCase
{
// ...
public function testUpdateQuantitiesWithException()
{
$this->setExpectedException('CartException');
$cart = new Cart();
$quantities = [ -1, 0, 0, 0, 0, 0 ];
$cart->updateQuantities($quantities); // 預期會產生一個 Exception
}
// ...
}
官方手冊參考
練習
思考哪些狀況可稱為異常?
思考看看 PHPUnit 不在測試裡使用
try ... catch
來捕捉異常的理由。