接下來我們就來開始寫程式吧,不過在寫程式之前要先有需求,所以就來定義一下我們購物車的需求吧
就來完成這三個需求吧,由於是要走單元測試,所以我們就先來寫 UnitTest吧
// tests/CartTest.php
namespace Recca0120\Cart\Tests;
use PHPUnit\Framework\TestCase;
class CartTest extends TestCase
{
/** @test */
public function 將商品加入購物車()
{
}
/** @test */
public function 商品必須有名稱單價數量()
{
}
/** @test */
public function 加總()
{
}
}
寫完單元測試後就直接來實作程式吧,我們就快速的完成第一個測試需求
// tests/CartTest.php
namespace Recca0120\Cart\Tests;
use Recca0120\Cart\Cart;
use PHPUnit\Framework\TestCase;
class CartTest extends TestCase
{
/** @test */
public function 將商品加入購物車()
{
$cart = new Cart();
$cart->put([
'name' => '商品01',
'price' => 100,
'qty' => 1,
]);
}
/** @test */
public function 商品必須有名稱單價數量()
{
}
/** @test */
public function 加總()
{
}
}
src/Cart.php
<?php
namespace Recca0120\Cart;
class Cart
{
private $items = [];
public function put($item)
{
array_push($this->items, $item);
return $this;
}
}
我們就完成了第一個案例需求,所以我們就可以報執行一次單元測試
vendor/bin/phpunit
這時會發現三個案例都報錯,沒錯因為沒有寫任何的 assertion,一個完整的測試一定要包含一個 assertion,測試才會亮綠燈,所以就來補上 assertion 吧,但會發現一件事情加入購物車的功能並無法進行任何驗證,所以就要來修改測試案例,讓測試能補上 assertion
// tests/CartTest.php
namespace Recca0120\Cart\Tests;
use Recca0120\Cart\Cart;
use PHPUnit\Framework\TestCase;
class CartTest extends TestCase
{
/** @test */
public function 將商品加入購物車並驗證商品有名稱單價數量()
{
$cart = new Cart();
$cart->put([
'name' => '商品01',
'price' => 100,
'qty' => 1,
]);
$this->assertArraySubset([[
'name' => '商品01',
'price' => 100,
'qty' => 1,
]], $cart->all());
}
/** @test */
public function 加總()
{
}
}
// src/Cart.php
namespace Recca0120\Cart;
class Cart
{
private $items = [];
public function put($item)
{
array_push($this->items, $item);
return $this;
}
public function all()
{
return $this->items;
}
}
這樣就完成第一個綠燈了,接下來完成今天最後一個功能加總
// tests/CartTest.php
namespace Recca0120\Cart\Tests;
use Recca0120\Cart\Cart;
use PHPUnit\Framework\TestCase;
class CartTest extends TestCase
{
/** @test */
public function 將商品加入購物車並驗證商品有名稱單價數量()
{
$cart = new Cart();
$cart->put([
'name' => '商品01',
'price' => 100,
'qty' => 1,
]);
$this->assertArraySubset([[
'name' => '商品01',
'price' => 100,
'qty' => 1,
]], $cart->all());
}
/** @test */
public function 加總()
{
$cart = new Cart();
$cart->put([
'name' => '商品01',
'price' => 100,
'qty' => 2,
]);
$cart->put([
'name' => '商品02',
'price' => 200,
'qty' => 1,
]);
$this->assertEquals(400, $cart->total());
}
}
// src/Cart.php
namespace Recca0120\Cart;
class Cart
{
private $items = [];
public function put($item)
{
array_push($this->items, $item);
return $this;
}
public function all()
{
return $this->items;
}
public function total()
{
return array_sum(array_map(function ($item) {
return $item['price'] * $item['qty'];
}, $this->items));
}
}
寫到這邊就會發現一件事情,其實就連單元測試也不應該太早把架構寫完,一樣會造成過早最佳化的問題
這個案例還有其他的測試手法,但希望大家好上手,所以暫時先用簡單的方法來驗證
不過要這樣寫必須要有一個條件是多一個公開方法是否合理,像購物車多了一個 all 可以查看購物車內有多少商品是合理的,所以這樣寫是沒問題,切記在寫物件導向時不必要公開的方法就不要公開啊 ...
至於另外的驗證方法,有機會再來深入討論
Hi Recca 大好
感覺 total()
這邊用 array_reduce
就可以了
public function total()
{
return array_reduce($this->items, function ($carry, $item) {
return $carry + $item['price'] * $item['qty'];
})
}
突然記了它的存在,反正有測試之後有機會再重構就好 XD