測試跟隨程式改變
除非是只用一次的程式,否則任何程式都有機會需要被維護,而維護就表示我們需要在程式上新增功能或進行修改。然而在新增或修改時,因為邏輯的改變就會需要調整測試。
為 Cart
類別加入運費計算
接下來我們要為 Cart.php
加入一個運費計算,當總金額未滿 $500 時,要加入 $20 的運費;另外我們把運費也當做是其中一個商品,它的價格是 $20 ,這在實務上是很常見的做法。
既然運費是其中一項商品,我們就把它加到 Cart::$prdoucts
裡,並設定一個運費鍵值常數 FREIGHT_KEY
:
private $products = [
// ... 加入運費商品
[
'name' => '運費',
'quantity' => 0,
'price' => 20,
'subtotal' => 0,
],
];
CONST FREIGHT_KEY = 6;
修改測試
然後我們修改 CartTest.php
的 provider
方法,讓總計未滿 $500 的測試要包含運費金額。
public function provider()
{
return [
[ [ 1, 0, 0, 0, 0, 0 ], 199 + 20 ],
[ [ 1, 0, 0, 2, 0, 0 ], 797 ],
];
}
商品數量改為 7 個:
public function testGetProducts()
{
// ...
$this->assertEquals(7, count($products));
// ...
}
執行測試:
C:\project> phpunit
PHPUnit 4.2.6 by Sebastian Bergmann.
Configuration read from C:\project\phpunit.xml
F.....
Time: 537 ms, Memory: 8.00Mb
There was 1 failure:
1) CartTest::testUpdateQuantitiesAndGetTotal with data set #0 (array(1, 0, 0, 0,
0, 0), 219)
Failed asserting that 199 matches expected 219.
C:\project\tests\CartTest.php:27
FAILURES!
Tests: 6, Assertions: 7, Failures: 1.
可以看到測試不通過,因為我們還沒加入運費判斷。
加入運費判斷
再來看原來的 updateQuantities
方法:
public function updateQuantities($quantities)
{
// 更新商品數量並算出小計
foreach ($quantities as $key => $qty) {
if (!is_numeric($qty) || (int) $qty < 0) {
throw new CartException("數量不正確,請輸入 0 或 0 以上的整數", 1);
}
$this->products[$key]['quantity'] = $qty;
$this->products[$key]['subtotal'] =
$this->products[$key]['quantity'] *
$this->products[$key]['price'];
}
// 計算總金額
$this->total = 0;
foreach ($this->products as $key => $product) {
$this->total += $product['subtotal'];
}
}
我們在計算總金額的後面加上一段運費的判斷:
// 運費
if ($this->total < 500) {
$this->products[self::FREIGHT_KEY]['quantity'] = 1;
$this->products[self::FREIGHT_KEY]['subtotal'] =
$this->products[self::FREIGHT_KEY]['quantity'] *
$this->products[self::FREIGHT_KEY]['price'];
// 加上運費
$this->total += $this->products[FREIGHT_KEY]['subtotal'];
} else {
$this->products[self::FREIGHT_KEY]['quantity'] = 0;
$this->products[self::FREIGHT_KEY]['subtotal'] =
$this->products[self::FREIGHT_KEY]['quantity'] *
$this->products[self::FREIGHT_KEY]['price'];
}
別忘了在 view.php
裡把運費的輸入欄位隱藏起來:
<?php if ($key !== Cart::FREIGHT_KEY): ?>
<input type="text" name="quantity[<?= $key ?>]" class="form-control" value="<?= $product['quantity'] ?>">
<?php else: ?>
<input type="hidden" name="quantity[<?= $key ?>]" value="0">
<?php endif; ?>
再執行一次測試:
C:\project> phpunit
PHPUnit 4.2.6 by Sebastian Bergmann.
Configuration read from C:\project\phpunit.xml
E.....
Time: 551 ms, Memory: 7.75Mb
There was 1 error:
1) CartTest::testUpdateQuantitiesAndGetTotal with data set #0 (array(1, 0, 0, 0,
0, 0), 219)
Use of undefined constant FREIGHT_KEY - assumed 'FREIGHT_KEY'
C:\project\Cart.php:92
C:\project\tests\CartTest.php:26
FAILURES!
Tests: 6, Assertions: 6, Errors: 1.
發現還是有錯,但 PHPUnit 幫我們指出在 Cart.php
第 92 行的 FREIGHT_KEY
有錯誤,因為我們沒有加上 self::
。修正後再執行一次,測試就通過了。
練習
思考看看有沒有更好的做法來加入運費?
思考看看有無沒測試到的狀況?