iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 5
0
自我挑戰組

單元測試開發購物車功能系列 第 5

Day05: 將商品重構到購物車

由於商品的物件都寫好了!
所以我們就來重構物車吧

今天也是直接上程式碼 ...

tests/CartTest.php

namespace Recca0120\Cart\Tests;

use Recca0120\Cart\Cart;
use Recca0120\Cart\Item;
use PHPUnit\Framework\TestCase;

class CartTest extends TestCase
{
    /** @test */
    public function 將商品加入購物車並驗證商品有名稱單價數量()
    {
        $item = $this->createItem('商品01', 100, 1);

        $cart = new Cart();
        $cart->put($item);

        $this->assertArraySubset([$item], $cart->items());
    }

    /** @test */
    public function 加總()
    {
        $cart = new Cart();
        $cart->put($this->createItem('商品01', 100, 2));
        $cart->put($this->createItem('商品02', 200, 1));

        $this->assertEquals(400, $cart->total());
    }

    private function createItem($name, $price, $qty)
    {
        return new Item([
            'name' => $name,
            'price' => $price,
            'quantity' => $qty,
        ]);
    }
}
// src/Cart.php

namespace Recca0120\Cart;

class Cart
{
    private $items = [];

    public function put($item)
    {
        array_push($this->items, $item);

        return $this;
    }

    public function items()
    {
        return $this->items;
    }

    public function total()
    {
        return array_sum(array_map(function ($item) {
            return $item->getPrice() * $item->getQuantity();
        }, $this->items));
    }
}

這樣就完成了程式的重構
不過今天要講的不是那麼單純的程式改版
在 PHP 裡有個 ArrayAccess interface 只要 implements 它,
就可以讓物件操作起來像 Array
所以只要實作它,其實Cart的程式其實連程式碼都不必修改 ...

所以先來進一步修改商品物件吧

// tests/Item.php

namespace Recca0120\Cart;

use ArrayAccess;

class Item implements ArrayAccess
{
    private $attributes = [];

    public function __construct($attributes = [])
    {
        $this->attributes = $attributes;
    }

    public function setName($name)
    {
        $this->attributes['name'] = $name;

        return $this;
    }

    public function getName()
    {
        return $this->attributes['name'];
    }

    public function setPrice($price)
    {
        $this->attributes['price'] = $price;

        return $this;
    }

    public function getPrice()
    {
        return $this->attributes['price'];
    }

    public function setQuantity($quantity)
    {
        $this->attributes['quantity'] = $quantity;

        return $this;
    }

    public function getQuantity()
    {
        return $this->attributes['quantity'];
    }

    public function toArray()
    {
        return $this->attributes;
    }

    public function offsetExists($offset)
    {
        return isset($this->attributes[$offset]);
    }

    public function offsetGet($offset)
    {
        return $this->attributes[$offset];
    }

    public function offsetSet($offset, $value)
    {
        $this->attributes[$offset] = $value;
    }

    public function offsetUnset($offset)
    {
        unset($this->attributes[$offset]);
    }
}
// tests/ItemTest.php

namespace Recca0120\Cart\Tests;

use Recca0120\Cart\Item;
use PHPUnit\Framework\TestCase;

class ItemTest extends TestCase
{
    /** @test */
    public function 測試商品屬性()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item($attributes);

        $this->assertEquals($attributes, $item->toArray());
    }

    /** @test */
    public function 使用mehtod來設定屬性()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item();

        $item->setName($attributes['name']);
        $this->assertSame($attributes['name'], $item->getName());

        $item->setPrice($attributes['price']);
        $this->assertSame($attributes['price'], $item->getPrice());

        $item->setQuantity($attributes['quantity']);
        $this->assertSame($attributes['quantity'], $item->getQuantity());

        $this->assertEquals($attributes, $item->toArray());
    }

    /** @test */
    public function 測試ArrayAccess()
    {
        $attributes = [
            'name' => '商品01',
            'price' => 100,
            'quantity' => 2,
        ];

        $item = new Item();

        $item['name'] = $attributes['name'];
        $this->assertSame($attributes['name'], $item['name']);

        $item['price'] = $attributes['price'];
        $this->assertSame($attributes['price'], $item['price']);

        $item['quantity'] = $attributes['quantity'];
        $this->assertSame($attributes['quantity'], $attributes['quantity']);

        $this->assertEquals($attributes, $item->toArray());
    }
}

改造完畢,
這樣就可以不用更改 Cart 的程式
並且可以讓 Item 有更多的操作方式

寫到這邊就能發現一件事情
寫測試想要寫的輕鬆,
其中一個要件就是對程式本身的熟悉度夠不夠高
熟悉度越高,寫起來相對輕鬆
熟悉度不高,就是改的地方多那麼一點點而已


上一篇
Day04: 將商品重構為物件
下一篇
Day06: 持續優化商品物件
系列文
單元測試開發購物車功能12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言