[Laravel] composer 套件開發
建立 Cart 套件
目標:
設計一個購物車物件,這個物件可以增加商品、計算總價、回傳商品總數量。
設計成能以 PSR-4 載入的套件。
重構商品
重構購物車
增加購物車功能
發佈套件
研究 CircleCI
建立專案
composer create-project laravel/laravel Cart --prefer-dist
移動到專案目錄下
cd Cart
建立套件
建立套件目錄,格式為 packges/開發商(作者)/套件名稱,並建立兩個資料夾分別為 src、tests
mkdir -p packges/ceparadise168/cart/src
mkdir -p packges/ceparadise168/cart/test
cd packges/ceparadise168/cart
初始化 composer 設定,安裝 phpunit
composer init
composer require phpunit/phpunit --dev
composer.json 如下
{
"name": "ceparadise168/cart",
"authors": [
{
"name": "Eric Tu",
"email": "ceparadise168@gmail.com"
}
],
"require": {},
"require-dev": {
"phpunit/phpunit": "^8.5"
},
"autoload": {
"psr-4": {
"Ceparadise168\\Cart\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Ceparadise168\\Cart\\Tests\\": "tests/"
}
}
}
讓 composer 根據我們指定的方式產生映射
composer dump-autoload
可以到這邊看結果
packges\ceparadise168\cart\vendor\composer\autoload_psr4.php
新增 packges\ceparadise168\cart\src\Cart.php
<?php
namespace Ceparadise168\Cart;
class Cart
{
private $items = [];
public function result()
{
return 'test';
}
}
驗證套件
回到專案根目錄底下的 composer.json,在 autoload 的地方加入對應資訊,
格式為 "Vendor\Namespace\": "path"
"autoload": {
"psr-4": {
"App\\": "app/",
"Ceparadise168\\Cart\\": "packges/ceparadise168/cart/src"
},
"classmap": [
"database/seeds",
"database/factories"
]
},
composer dump-autoload
在 routes\web.php 中修改 / 回傳方便驗證結果
<?php
use Illuminate\Support\Facades\Route;
use Ceparadise168\Cart\Cart;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
/*
return view('welcome');
*/
$cart = new Cart();
return $cart->result();
});
利用 php artisan serve 啟動專案並訪問 http://127.0.0.1:8000,就可以看到 test 了
$ php artisan serve
Laravel development server started: http://127.0.0.1:8000
[Wed Jul 8 07:11:15 2020] 127.0.0.1:55141 [200]: /favicon.ico
規劃及開發 Cart 套件
準備測試環境
回到套件目錄準備測試環境
cd packges/ceparadise168/cart
先前已經安裝過 phpunit 了,直接下指令生成 phpunit.xml
$ vendor/bin/phpunit --generate-configuration
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Generating phpunit.xml in C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart
Bootstrap script (relative to path shown above; default: vendor/autoload.php):
Tests directory (relative to path shown above; default: tests):
Source directory (relative to path shown above; default: src):
Generated phpunit.xml in C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart
建立一個 CartTest
touch tests/CartTest.php
<?php
use PHPUnit\Framework\TestCase;
class CartTest extends TestCase
{
public function testHello()
{
$string = 'hello';
$this->assertEquals('hello', $string);
}
}
執行測試確認測試功能正常
$ ./vendor/bin/phpunit
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.31 with Xdebug 2.8.1
Configuration: C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\phpunit.xml
. 1 / 1 (100%)
Time: 489 ms, Memory: 4.00 MB
OK (1 test, 1 assertion)
採用 TDD 方式新增購物車基本功能
- 增加商品
- 取得所有商品
- 計算總價
- 計算總數量
撰寫測試增加商品到購物車的測試
public function testPutItemToCartAndAssertCartItem()
{
$cart = new Cart();
$item = [
'name' => 'pen',
'price' => 100,
'qty' => 1
];
$cart->putItem($item);
$this->assertEquals([], array_diff_assoc($item, $cart->getItems()));
}
執行測試,發現得到紅燈,測試失敗。 因為 Cart 還沒有實作 putItem()、getItems()
$ ./vendor/bin/phpunit
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.31 with Xdebug 2.8.1
Configuration: C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\phpunit.xml
E. 2 / 2 (100%)
Time: 470 ms, Memory: 4.00 MB
There was 1 error:
1) CartTest::testPutItemToCartAndAssertCartItem
Error: Call to undefined method Ceparadise168\Cart\Cart::putItem()
C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\tests\CartTest.php:23
ERRORS!
Tests: 2, Assertions: 1, Errors: 1.
實作 putItem()、getItems()
<?php
namespace Ceparadise168\Cart;
class Cart
{
private $items = [];
public function result()
{
return 'test';
}
public function putItem($item = [])
{
$this->items[] = $item;
return $this;
}
public function getItems()
{
return $this->items;
}
}
再次測試,得到綠燈,測試通過。
$ ./vendor/bin/phpunit
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.31 with Xdebug 2.8.1
Configuration: C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\phpunit.xml
.. 2 / 2 (100%)
Time: 461 ms, Memory: 4.00 MB
OK (2 tests, 2 assertions)
測試計算總價
public function testGetCartTotal()
{
$cart = new Cart();
$item = [
'name' => 'pen',
'price' => 100,
'qty' => 1
];
$cart->putItem($item);
$item = [
'name' => 'eraser',
'price' => 200,
'qty' => 2
];
$cart->putItem($item);
$this->assertEquals(500, $cart->total());
}
紅燈
$ ./vendor/bin/phpunit
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.31 with Xdebug 2.8.1
Configuration: C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\phpunit.xml
..E 3 / 3 (100%)
Time: 474 ms, Memory: 4.00 MB
There was 1 error:
1) CartTest::testGetCartTotal
Error: Call to undefined method Ceparadise168\Cart\Cart::total()
C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\tests\CartTest.php:46
ERRORS!
Tests: 3, Assertions: 2, Errors: 1.
增加計算總價方法
public function total()
{
$items = $this->getItems();
$total = 0;
foreach ($items as $item) {
$total += $item['price'] * $item['qty'];
}
return $total;
}
綠燈
$ ./vendor/bin/phpunit
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.31 with Xdebug 2.8.1
Configuration: C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\phpunit.xml
... 3 / 3 (100%)
Time: 469 ms, Memory: 4.00 MB
OK (3 tests, 3 assertions)
測試計算商品數量
public function testTotalQuantityShouldGetTotalQuantityOfCartItems()
{
$cart = new Cart();
$item = [
'name' => 'pen',
'price' => 100,
'qty' => 1
];
$cart->putItem($item);
$item = [
'name' => 'eraser',
'price' => 200,
'qty' => 2
];
$cart->putItem($item);
$this->assertEquals(500, $cart->getTotalQuantity());
}
紅燈
$ ./vendor/bin/phpunit
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.31 with Xdebug 2.8.1
Configuration: C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\phpunit.xml
...E 4 / 4 (100%)
Time: 471 ms, Memory: 4.00 MB
There was 1 error:
1) CartTest::testTotalQuantityShouldGetTotalQuantityOfCartItems
Error: Call to undefined method Ceparadise168\Cart\Cart::getTotalQuantity()
C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\tests\CartTest.php:67
ERRORS!
Tests: 4, Assertions: 3, Errors: 1.
增加計算商品數量方法
public function getTotalQuantity()
{
$items = $this->getItems();
$totalQuantity = 0;
foreach ($items as $item) {
$totalQuantity += $item['qty'];
}
return $totalQuantity;
}
綠燈
$ ./vendor/bin/phpunit
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Runtime: PHP 7.2.31 with Xdebug 2.8.1
Configuration: C:\Users\cepar\Desktop\projects\TQ\Cart\packges\ceparadise168\cart\phpunit.xml
.... 4 / 4 (100%)
Time: 465 ms, Memory: 4.00 MB
OK (4 tests, 4 assertions)
整合 CircleCi
# PHP CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-php/ for more details
#
version: 2
jobs:
build:
docker:
# Specify the version you desire here
- image: circleci/php:7.1-node-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# Using the RAM variation mitigates I/O contention
# for database intensive operations.
# - image: circleci/mysql:5.7-ram
#
# - image: redis:2.8.19
steps:
- checkout
- run: sudo apt update # PHP CircleCI 2.0 Configuration File# PHP CircleCI 2.0 Configuration File sudo apt install zlib1g-dev libsqlite3-dev
- run: sudo docker-php-ext-install zip
# Download and cache dependencies
- restore_cache:
keys:
# "composer.lock" can be used if it is committed to the repo
- v1-dependencies-{{ checksum "composer.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: composer install -n --prefer-dist
- save_cache:
key: v1-dependencies-{{ checksum "composer.json" }}
paths:
- ./vendor
- restore_cache:
keys:
- node-v1-{{ checksum "package.json" }}
- node-v1-
- run: yarn install
- save_cache:
key: node-v1-{{ checksum "package.json" }}
paths:
- node_modules
# prepare the database
- run: touch storage/testing.sqlite
- run: php artisan migrate --env=testing --database=sqlite_testing --force
# run tests with phpunit or codecept
#- run: ./vendor/bin/phpunit
- run: ./vendor/bin/codecept build
- run: ./vendor/bin/codecept run
最後面測試的 block 調整如下
#- run: ./vendor/bin/codecept build
#- run: ./vendor/bin/codecept run
- run: ./vendor/bin/phpunit
- run: ./vendor/bin/phpunit -c ./packges/ceparadise168/cart/phpunit.xml
建置失敗
PHP 版本太舊,找看看官方有沒有更新的
https://hub.docker.com/r/circleci/php/tags?page=1&name=7.2-node-browsers
調整 config.yaml 檔案修正以下問題
commit 5737444eb6496c82becd044743ca19af805d6fb8 (HEAD, origin/circleci-project-setup)
Author: eric_tu <ceparadise168@gmail.com>
Date: Thu Jul 9 03:00:52 2020 +0800
[Bug] Fix no application encryption key has been specified
- 建置測試流程新增測試環境 APP_KEY
commit 2289ca03591fdcb252ce8f850ade4c08f30e24e7
Author: eric_tu <ceparadise168@gmail.com>
Date: Thu Jul 9 02:39:53 2020 +0800
[Bug] 修正 circleci config.yaml sed 未執行
commit c1cb28d5d8ded77f5fbef741ec4836405b505f7f
Author: eric_tu <ceparadise168@gmail.com>
Date: Thu Jul 9 02:34:52 2020 +0800
[Bug] Fix testing env
- circleci confix 新增複製 .env.testing 設定
- 調整測試用資料庫設定
commit 80ece6c05dfc9e84124cbaa33e8902779359b513
Author: eric_tu <ceparadise168@gmail.com>
Date: Thu Jul 9 02:08:41 2020 +0800
[Fix] Update circleci images with php72
調整內容如下
# prepare the database
- run: cp .env.example .env.testing
- run: php artisan key:generate --env=testing
- run: sed -i 's/DB_CONNECTION=mysql/DB_CONNECTION=sqlite/' .env.testing
- run: sed -i 's/DB_DATABASE=laravel/DB_DATABASE=:memory:/' .env.testing
- run: touch storage/testing.sqlite
- run: php artisan migrate --env=testing --database=sqlite --force
# run tests with phpunit or codecept
#- run: ./vendor/bin/phpunit
#- run: ./vendor/bin/codecept build
#- run: ./vendor/bin/codecept run
- run: ./vendor/bin/phpunit
- run: ./vendor/bin/phpunit -c ./packges/ceparadise168/cart/phpunit.xml
References:
Laravel Packages Development 套件開發
留言
張貼留言