iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 2
0
自我挑戰組

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

Day 02: 撰寫購物車程式

  • 分享至 

  • xImage
  •  

接下來我們就來開始寫程式吧,不過在寫程式之前要先有需求,所以就來定義一下我們購物車的需求吧

  • 可將商品加入購物車
  • 商品必須有名稱、單價、數量
  • 可以計算總價

就來完成這三個需求吧,由於是要走單元測試,所以我們就先來寫 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 可以查看購物車內有多少商品是合理的,所以這樣寫是沒問題,切記在寫物件導向時不必要公開的方法就不要公開啊 ...
至於另外的驗證方法,有機會再來深入討論


上一篇
Day 01: 安裝 PHPUnit
下一篇
Day 03: 第一次重構
系列文
單元測試開發購物車功能12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
clouding
iT邦新手 5 級 ‧ 2019-03-01 00:47:51

Hi Recca 大好

感覺 total() 這邊用 array_reduce 就可以了

public function total()
{
    return array_reduce($this->items, function ($carry, $item) {
        return $carry + $item['price'] * $item['qty'];
    })
}
recca0120 iT邦新手 4 級 ‧ 2023-09-16 21:22:45 檢舉

突然記了它的存在,反正有測試之後有機會再重構就好 XD

我要留言

立即登入留言