Beginning PHPUnit
-
Upload
jace-ju -
Category
Technology
-
view
2.796 -
download
3
Transcript of Beginning PHPUnit
![Page 1: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/1.jpg)
Beginning PHPUnit從今天起進入測試的世界
![Page 2: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/2.jpg)
關於我
Jace Ju / jaceju / 大澤木小鐵
PHP Smarty 樣版引擎 作者
Plurk: http://www.plurk.com/jaceju 歡迎追我 >////<
![Page 3: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/3.jpg)
接下來的內容都是基本功
不會有太深的專有名詞
![Page 4: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/4.jpg)
今日重點
![Page 5: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/5.jpg)
•如何用 PHPUnit 寫測試
今日重點
![Page 6: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/6.jpg)
•如何用 PHPUnit 寫測試
•基本的 PHPUnit 用法
今日重點
![Page 7: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/7.jpg)
•如何用 PHPUnit 寫測試
•基本的 PHPUnit 用法
•如何搭配測試來做重構
今日重點
![Page 8: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/8.jpg)
•如何用 PHPUnit 寫測試
•基本的 PHPUnit 用法
•如何搭配測試來做重構•如何用測試找出錯誤
今日重點
![Page 9: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/9.jpg)
進入主題
![Page 10: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/10.jpg)
Question 1
![Page 11: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/11.jpg)
你如何測試
你的 Web 應用程式?
![Page 12: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/12.jpg)
瀏覽器打開來
一個步驟一個步驟測試
![Page 13: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/13.jpg)
這叫測試?
![Page 14: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/14.jpg)
這叫測試?
這叫自虐!
![Page 15: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/15.jpg)
Question 2
![Page 16: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/16.jpg)
你認為你交給客戶的程式
都是沒問題的嗎?
![Page 17: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/17.jpg)
任何程式都不可能
完美考慮到
所有使用者的狀況
![Page 18: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/18.jpg)
客戶一定會踩中你沒有想到的地雷民明書房 - 軟體莫非定律一百則
![Page 19: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/19.jpg)
Question 3
![Page 20: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/20.jpg)
你確定每次抓完一個 bug 後
不會生出其他 bugs 嗎?
![Page 21: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/21.jpg)
Bugs 總會在
改了幾行程式碼後來找你
![Page 22: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/22.jpg)
每次改完程式
都一定要從頭測試
![Page 23: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/23.jpg)
這時候我們需要
用程式來寫測試
![Page 24: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/24.jpg)
Example
![Page 25: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/25.jpg)
來個簡單的
計算 1 + 2 + 3 + ... + N = ?
![Page 26: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/26.jpg)
先來看看
範例專案目錄結構
![Page 27: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/27.jpg)
project
├── application
└── library
│ └── Math.php
└── run_test.php
範例專案目錄結構
專案目錄
應用程式目錄
套件目錄
欲測試的類別
測試程式
![Page 28: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/28.jpg)
project
├── application
└── library
│ └── Math.php
└── run_test.php
範例專案目錄結構
專案目錄
應用程式目錄
套件目錄
欲測試的類別
測試程式
![Page 29: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/29.jpg)
project
├── application
└── library
│ └── Math.php
└── run_test.php
範例專案目錄結構
專案目錄
應用程式目錄
套件目錄
欲測試的類別
測試程式
![Page 30: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/30.jpg)
project
├── application
└── library
│ └── Math.php
└── run_test.php
範例專案目錄結構
專案目錄
應用程式目錄
套件目錄
欲測試的類別
測試程式
![Page 31: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/31.jpg)
project
├── application
└── library
│ └── Math.php
└── run_test.php
範例專案目錄結構
專案目錄
應用程式目錄
套件目錄
欲測試的類別
測試程式
![Page 32: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/32.jpg)
從 Math.php 開始
![Page 33: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/33.jpg)
Math.php
![Page 34: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/34.jpg)
Math.php
這裡的類別扮演了命名空間的角色
<?phpclass Math{
}
![Page 35: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/35.jpg)
Math.php
加入 Math::sum 方法
<?phpclass Math{ public static function sum($min, $max) { $sum = 0; for ($i = $min; $i <= $max; $i++) { $sum += $i; } return $sum; }}
![Page 36: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/36.jpg)
Math.php
// 接續上一頁if (defined('TEST_MODE')) {
}
利用 TEST_MODE 常數來進入測試
![Page 37: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/37.jpg)
Math.php
測試 1 加到 10 的結果
// 接續上一頁if (defined('TEST_MODE')) { // Test 1 $result = Math::sum(1, 10); if (55 !== $result) { echo "Test 1 failed!\n"; } else { echo "Test 1 OK!\n"; }
}
![Page 38: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/38.jpg)
Math.php
// 接續上一頁if (defined('TEST_MODE')) { // Test 1 $result = Math::sum(1, 10); if (55 !== $result) { echo "Test 1 failed!\n"; } else { echo "Test 1 OK!\n"; }
// Test 2 $result = Math::sum(1, 100); if (5050 !== $result) { echo "Test 2 failed!\n"; } else { echo "Test 2 OK!\n"; }}
測試 1 加到 100 的結果
![Page 39: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/39.jpg)
接著看 run_test.php
![Page 40: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/40.jpg)
run_test.php
![Page 41: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/41.jpg)
run_test.php
<?phpdefine('TEST_MODE', true);定義 TEST_MODE
常數
![Page 42: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/42.jpg)
run_test.php
引用欲測試的類別
<?phpdefine('TEST_MODE', true);require_once __DIR__ . '/library/Math.php';
![Page 43: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/43.jpg)
執行測試
![Page 44: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/44.jpg)
執行測試
在命令列執行該指令
# php run_test.php
![Page 45: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/45.jpg)
執行測試# php run_test.phpTest 1 OK!Test 2 OK!測試成功
![Page 46: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/46.jpg)
但是測試不是只有
比對值的相等
![Page 47: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/47.jpg)
是否為某變數類型
但是測試不是只有
比對值的相等
![Page 48: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/48.jpg)
陣列是否包含某值
是否為某變數類型
但是測試不是只有
比對值的相等
![Page 49: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/49.jpg)
但是測試不是只有
比對值的相等
陣列是否包含某值
是否為某變數類型
類別是否有某屬性
![Page 50: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/50.jpg)
陣列是否包含某值
是否為某變數類型
類別是否有某屬性是否有預期的錯誤
但是測試不是只有
比對值的相等
![Page 51: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/51.jpg)
每一種比對
都要寫好多程式
![Page 52: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/52.jpg)
結果用程式寫測試
反而增加了負擔
![Page 53: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/53.jpg)
如果有工具來幫我們
做這些事就好了...
![Page 54: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/54.jpg)
主角終於姍姍來遲
![Page 57: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/57.jpg)
屬於 xUnit 家族
http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks
![Page 58: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/58.jpg)
# pear channel-discover pear.symfony-project.com# pear install symfony/YAML# pear channel-discover pear.phpunit.de# pear channel-discover components.ez.no# pear install -o phpunit/phpunit
安裝
![Page 59: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/59.jpg)
改用 PHPUnit 測試
![Page 60: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/60.jpg)
準備專案的測試環境
![Page 61: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/61.jpg)
project
├── application
└── library
└── Math.php
範例專案目錄結構
回到原先的專案目錄
![Page 62: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/62.jpg)
project
├── application
├── library
│ └── Math.php
└── tests
範例專案目錄結構
新增一個測試目錄
![Page 63: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/63.jpg)
project
├── application
├── library
│ └── Math.php
└── tests
├── application
└── library
範例專案目錄結構
建立與專案目錄下一模一樣的目錄結構
(除了 tests 以外)
![Page 64: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/64.jpg)
接下來要建立測試
![Page 65: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/65.jpg)
project
├── application
├── library
│ └── Math.php
└── tests
├── application
└── library
範例專案目錄結構
我們要測試的是這個類別
![Page 66: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/66.jpg)
project
├── application
├── library
│ └── Math.php
└── tests
├── application
└── library
└── MathTest.php
範例專案目錄結構
在慣例上我們會在測試目錄下對應的
library 目錄中建立一個 MathTest.php
![Page 67: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/67.jpg)
MathTest.php
![Page 68: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/68.jpg)
MathTest.php
<?php
class MathTest{
}
定義一個 Test Case 類別
![Page 69: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/69.jpg)
MathTest.php
<?php
class MathTest{
}
慣例上類別名稱與檔名相同
![Page 70: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/70.jpg)
MathTest.php
引用我們要測試的類別檔案
<?phprequire_once __DIR__ . '/Math.php';class MathTest{
}
![Page 71: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/71.jpg)
MathTest.php
繼承 PHPUnit 的 TestCase 類別
<?phprequire_once __DIR__ . '/Math.php';class MathTest extends PHPUnit_Framework_TestCase{
}
![Page 72: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/72.jpg)
MathTest.php
加入一個測試
<?phprequire_once __DIR__ . '/Math.php';class MathTest extends PHPUnit_Framework_TestCase{ public function testSum() {
}}
![Page 73: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/73.jpg)
MathTest.php
測試函式的開頭一定要為 test
<?phprequire_once __DIR__ . '/Math.php';class MathTest extends PHPUnit_Framework_TestCase{ public function testSum() {
}}
![Page 74: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/74.jpg)
MathTest.php
test 後面通常是要測試的方法名稱也可以是一個
CamelCase 的句子
<?phprequire_once __DIR__ . '/Math.php';class MathTest extends PHPUnit_Framework_TestCase{ public function testSum() {
}}
![Page 75: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/75.jpg)
MathTest.php
把原來測試的方式改用 PHPUnit 的
assertions
<?phprequire_once __DIR__ . '/Math.php';class MathTest extends PHPUnit_Framework_TestCase{ public function testSum() { $this->assertEquals(55, Math::sum(1, 10)); $this->assertEquals(5050, Math::sum(1, 100)); }}
![Page 76: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/76.jpg)
MathTest.php
<?phprequire_once __DIR__ . '/Math.php';class MathTest extends PHPUnit_Framework_TestCase{ public function testSum() { $this->assertEquals(55, Math::sum(1, 10)); $this->assertEquals(5050, Math::sum(1, 100)); }}
這邊是預期的結果
![Page 77: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/77.jpg)
MathTest.php
<?phprequire_once __DIR__ . '/Math.php';class MathTest extends PHPUnit_Framework_TestCase{ public function testSum() { $this->assertEquals(55, Math::sum(1, 10)); $this->assertEquals(5050, Math::sum(1, 100)); }}
這邊是實際得到的結果
![Page 78: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/78.jpg)
執行測試# phpunit tests/library/MathTest
直接在 console 下指令
不需要指定完整 php 檔名
![Page 79: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/79.jpg)
執行測試# phpunit tests/library/MathTestPHPUnit 3.5.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 5.25Mb
OK (1 test, 2 assertions)
這樣就算測試成功了
![Page 80: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/80.jpg)
執行測試# phpunit tests/library/MathTestPHPUnit 3.5.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 5.25Mb
OK (1 test, 2 assertions)總共有一個測試兩個 assertions
![Page 81: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/81.jpg)
我看到你們
心中的疑問了
![Page 82: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/82.jpg)
phpunit 指令會自動載入
PHPUnit 相關類別
![Page 83: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/83.jpg)
每個 Test Case 類別
都可以有多組 Tests也就是 testXxxx 方法
![Page 84: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/84.jpg)
每組 Test
都可以有多個 assertions
![Page 85: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/85.jpg)
不過類似的 assertions 太多
寫起來感覺很麻煩
![Page 86: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/86.jpg)
用 Data Provider 來提供測試資料
![Page 87: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/87.jpg)
MathTest.php
先將原來的 MathTest 內容修改成這樣
<?phprequire_once dirname(dirname(__DIR__)) . '/library/Math.php';class MathTest extends PHPUnit_Framework_TestCase{
public function testSum() { $this->assertEquals(55, Math::sum(1, 10 )); }
}
![Page 88: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/88.jpg)
MathTest.php
<?phprequire_once dirname(dirname(__DIR__)) . '/library/Math.php';class MathTest extends PHPUnit_Framework_TestCase{
public function testSum($expected, $min, $max) { $this->assertEquals(55, Math::sum(1, 10 )); }
}
加上方法參數
![Page 89: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/89.jpg)
MathTest.php
<?phprequire_once dirname(dirname(__DIR__)) . '/library/Math.php';class MathTest extends PHPUnit_Framework_TestCase{
public function testSum($expected, $min, $max) { $this->assertEquals($expected, Math::sum($min, $max)); }
}
將預期結果與實際結果
都改為引用參數
![Page 90: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/90.jpg)
MathTest.php
加入提供資料的 public 方法
<?phprequire_once dirname(dirname(__DIR__)) . '/library/Math.php';class MathTest extends PHPUnit_Framework_TestCase{
public function testSum($expected, $min, $max) { $this->assertEquals($expected, Math::sum($min, $max)); }
public function myDataProvider() { return array( array(55, 1, 10), array(5050, 1, 100) ); }}
![Page 91: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/91.jpg)
MathTest.php
每組資料都對應到上面的方法參數
<?phprequire_once dirname(dirname(__DIR__)) . '/library/Math.php';class MathTest extends PHPUnit_Framework_TestCase{
public function testSum($expected, $min, $max) { $this->assertEquals($expected, Math::sum($min, $max)); }
public function myDataProvider() { return array( array(55, 1, 10), array(5050, 1, 100) ); }}
![Page 92: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/92.jpg)
MathTest.php
利用 PHPUnit 的 @dataProvider 這個 annotation
來引用 data provider
<?phprequire_once dirname(dirname(__DIR__)) . '/library/Math.php';class MathTest extends PHPUnit_Framework_TestCase{ /** * @dataProvider myDataProvider */ public function testSum($expected, $min, $max) { $this->assertEquals($expected, Math::sum($min, $max)); }
public function myDataProvider() { return array( array(55, 1, 10), array(5050, 1, 100) ); }}
![Page 93: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/93.jpg)
執行測試# phpunit tests/library/MathTest
再測試一次
![Page 94: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/94.jpg)
執行測試# phpunit tests/library/MathTestPHPUnit 3.5.15 by Sebastian Bergmann.
..
Time: 0 seconds, Memory: 5.25Mb
OK (2 tests, 2 assertions)這次變成了兩個 tests
![Page 95: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/95.jpg)
Provider 所提供的每組資料
都會被視為一個 Test
![Page 96: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/96.jpg)
Situation
![Page 97: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/97.jpg)
如果要給
Math::sum 的程式碼一個分數...
![Page 98: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/98.jpg)
如果要給
Math::sum 的程式碼一個分數...
![Page 99: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/99.jpg)
小學生都知道
1 + 2 + 3 + ... + N
梯形公式
=
![Page 100: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/100.jpg)
重構 Math::sum 的程式碼
![Page 101: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/101.jpg)
Math.php
回到 Math.php<?phpclass Math{ public static function sum($min, $max) { $sum = 0; for ($i = $min; $i <= $max; $i++) { $sum += $i; } return $sum; }}
![Page 102: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/102.jpg)
Math.php
拿掉原來的運算式
<?phpclass Math{ public static function sum($min, $max) { $sum = 0;
return $sum; }}
![Page 103: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/103.jpg)
Math.php
改用公式解
<?phpclass Math{ public static function sum($min, $max) { $sum = $min + $max * $max / 2;
return $sum; }}
![Page 104: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/104.jpg)
執行測試# phpunit tests/library/MathTest
一樣是 MathTest.php
![Page 105: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/105.jpg)
執行測試# phpunit tests/library/MathTestPHPUnit 3.5.15 by Sebastian Bergmann.
F
Time: 0 seconds, Memory: 6.00Mb
There was 1 failure:
1) MathTest03::testSumFailed asserting that <integer:51> matches expected <integer:55>.
/path/to/tests/library/MathTest.php:7
FAILURES!Tests: 1, Assertions: 1, Failures: 1.
出現測試錯誤了
![Page 106: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/106.jpg)
執行測試# phpunit tests/library/MathTestPHPUnit 3.5.15 by Sebastian Bergmann.
F
Time: 0 seconds, Memory: 6.00Mb
There was 1 failure:
1) MathTest03::testSumFailed asserting that <integer:51> matches expected <integer:55>.
/path/to/tests/library/MathTest.php:7
FAILURES!Tests: 1, Assertions: 1, Failures: 1.
預期結果為 55但是實際卻是 51
![Page 107: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/107.jpg)
Math.php
看來問題出在剛剛改的程式碼
<?phpclass Math{ /** * 計算總合 */ public static function sum($min, $max) { $sum = $min + $max * $max / 2;
return $sum; }}
![Page 108: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/108.jpg)
Math.php
原來忘了先乘除後加減
<?phpclass Math{ /** * 計算總合 */ public static function sum($min, $max) { $sum = ($min + $max) * $max / 2;
return $sum; }}
![Page 109: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/109.jpg)
執行測試# phpunit tests/library/MathTestPHPUnit 3.5.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 5.25Mb
OK (1 test, 2 assertions)
測試成功了
![Page 110: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/110.jpg)
測試能確保我們的重構
是在正確的方向
![Page 111: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/111.jpg)
再來點複雜的
![Page 112: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/112.jpg)
用物件組出
SQL 的 Select 語法在 ORM Framework 中很常見
![Page 113: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/113.jpg)
概念設計
![Page 114: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/114.jpg)
概念設計
•類別: DbSelect
![Page 115: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/115.jpg)
概念設計
•類別: DbSelect
•方法:
![Page 116: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/116.jpg)
概念設計
•類別: DbSelect
•方法:‣ from :對應到 SELECT 語法的 FROM
![Page 117: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/117.jpg)
概念設計
•類別: DbSelect
•方法:‣ from :對應到 SELECT 語法的 FROM
‣ cols :對應到 SELECT 語法的欄位,預設為 *
![Page 118: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/118.jpg)
$select = new DbSelect();echo $select->from(‘table’);
SELECT * FROM table
Example 1
![Page 119: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/119.jpg)
$select = new DbSelect();echo $select->from(‘table’)->cols(array( ‘col_a’, ‘col_b’));
SELECT col_a, col_b FROM table
Example 2
![Page 120: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/120.jpg)
project
├── application
├── library
│ └── DbSelect.php
└── tests
├── application
└── library
└── DbSelectTest.php
範例專案目錄結構
準備好這兩個檔案
![Page 121: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/121.jpg)
DbSelect.php
先建立 DbSelect 類別
但我們還不知道怎麼實作
<?phpclass DbSelect{
}
![Page 122: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/122.jpg)
DbSelectTest.php
所以我們先建立測試類別
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{
}
![Page 123: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/123.jpg)
DbSelectTest.php
在設計中類別會有一個 from 方法
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ public function testFrom() {
}
}
![Page 124: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/124.jpg)
DbSelectTest.php
先寫出了它的用法與預期產生的結果做為測試用
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ public function testFrom() { $select = new DbSelect(); $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); }
}
![Page 125: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/125.jpg)
DbSelect.php
回到 DbSelect.php<?phpclass DbSelect{
}
![Page 126: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/126.jpg)
DbSelect.php
先加入 from 方法
<?phpclass DbSelect{
public function from($table) {
}
}
![Page 127: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/127.jpg)
DbSelect.php
加入 __toString 方法
<?phpclass DbSelect{
public function from($table) {
}
public function __toString() {
}}
![Page 128: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/128.jpg)
DbSelect.php
先寫出可以通過測試的程式
<?phpclass DbSelect{
public function from($table) {
}
public function __toString() {
return 'SELECT * FROM test'; }}
![Page 129: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/129.jpg)
執行測試# phpunit tests/library/DbSelectTestPHPUnit 3.5.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 5.25Mb
OK (1 test, 1 assertions)
![Page 130: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/130.jpg)
我知道這看起來很蠢
![Page 131: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/131.jpg)
DbSelect.php
把 table 改成可以置換
<?phpclass DbSelect{
public function from($table) {
}
public function __toString() {
return 'SELECT * FROM ' . $this->_table; }}
![Page 132: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/132.jpg)
DbSelect.php
加入 $_table 屬性
<?phpclass DbSelect{ protected $_table = 'table';
public function from($table) {
}
public function __toString() {
return 'SELECT * FROM ' . $this->_table; }}
![Page 133: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/133.jpg)
DbSelect.php
from 方法是一個有驗證的 setter
<?phpclass DbSelect{ protected $_table = 'table';
public function from($table) { if (!preg_match('/[0-9a-z]+/i', $table)) { throw new IllegalNameException('Illegal Table Name'); } $this->_table = $table; return $this; }
public function __toString() {
return 'SELECT * FROM ' . $this->_table; }}
![Page 134: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/134.jpg)
執行測試# phpunit tests/library/DbSelectTestPHPUnit 3.5.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 5.25Mb
OK (1 test, 1 assertions)
![Page 135: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/135.jpg)
Design Write Test Coding→ →Direction Find Target Fire→ →
![Page 136: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/136.jpg)
完成一個功能並測試成功後
就可以繼續下一個功能
![Page 137: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/137.jpg)
DbSelectTest.php
回到 DbSelectTest.php
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ public function testFrom() { $select = new DbSelect(); $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); }
}
![Page 138: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/138.jpg)
DbSelectTest.php
補上 cols 方法的測試
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ public function testFrom() { $select = new DbSelect(); $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); } public function testCols() { $select = new DbSelect(); $select->from('test')->cols(array( 'col_a', 'col_b', )); $this->assertEquals('SELECT col_a, col_b FROM test', $select->__toString()); }}
![Page 139: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/139.jpg)
DbSelect.php
回到 DbSelect.php<?phpclass DbSelect{ protected $_table = 'table';
public function from($table) { if (!preg_match('/[0-9a-z]+/i', $table)) { throw new IllegalNameException('Illegal Table Name'); } $this->_table = $table; return $this; }
public function __toString() {
return 'SELECT * FROM ' . $this->_table; }}
![Page 140: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/140.jpg)
DbSelect.php
加入 cols 方法
<?phpclass DbSelect{ protected $_table = 'table';
public function from($table) { if (!preg_match('/[0-9a-z]+/i', $table)) { throw new IllegalNameException('Illegal Table Name'); } $this->_table = $table; return $this; } public function cols($cols) { $this->_cols = (array) $cols; return $this; } public function __toString() {
return 'SELECT * FROM ' . $this->_table; }}
![Page 141: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/141.jpg)
DbSelect.php
加上 $_cols 屬性
<?phpclass DbSelect{ protected $_table = 'table'; protected $_cols = '*'; public function from($table) { if (!preg_match('/[0-9a-z]+/i', $table)) { throw new IllegalNameException('Illegal Table Name'); } $this->_table = $table; return $this; } public function cols($cols) { $this->_cols = (array) $cols; return $this; } public function __toString() {
return 'SELECT * FROM ' . $this->_table; }}
![Page 142: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/142.jpg)
DbSelect.php
用 $_cols 屬性替換掉原來的 *
<?phpclass DbSelect{ protected $_table = 'table'; protected $_cols = '*'; public function from($table) { if (!preg_match('/[0-9a-z]+/i', $table)) { throw new IllegalNameException('Illegal Table Name'); } $this->_table = $table; return $this; } public function cols($cols) { $this->_cols = (array) $cols; return $this; } public function __toString() { $cols = implode(', ', (array) $this->_cols); return 'SELECT ' . $cols . ' FROM ' . $this->_table; }}
![Page 143: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/143.jpg)
執行測試# phpunit tests/library/DbSelectTestPHPUnit 3.5.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 5.25Mb
OK (2 test, 2 assertions)兩個測試都通過了
![Page 144: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/144.jpg)
通常新增的功能
不會影響舊的功能
![Page 145: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/145.jpg)
如果舊測試發生錯誤
就表示新的功能帶來了 bug
![Page 146: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/146.jpg)
每個測試所會用到的資源
都要隔離並重新初始化
![Page 147: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/147.jpg)
DbSelectTest.php
回到 DbSelectTest.php
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ public function testFrom() { $select = new DbSelect(); $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); } public function testCols() { $select = new DbSelect(); $select->from('test')->cols(array( 'col_a', 'col_b', )); $this->assertEquals('SELECT col_a, col_b FROM test', $select->__toString()); }}
![Page 148: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/148.jpg)
DbSelectTest.php
每個測試都需要 new DbSelect()
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ public function testFrom() { $select = new DbSelect(); $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); } public function testCols() { $select = new DbSelect(); $select->from('test')->cols(array( 'col_a', 'col_b', )); $this->assertEquals('SELECT col_a, col_b FROM test', $select->__toString()); }}
![Page 149: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/149.jpg)
DRYDon't Repeat Yourself
![Page 150: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/150.jpg)
Fixture每個測試必定會用的資源
![Page 151: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/151.jpg)
DbSelectTest.php
先拿掉原來的 new DbSelect()
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{
public function testFrom() { $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); } public function testCols() { $select->from('test')->cols(array('col_a', 'col_b')); $this->assertEquals('SELECT col_a, col_b FROM test', $select->__toString()); }
}
![Page 152: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/152.jpg)
DbSelectTest.php
加入一個 fixture
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ protected $_select;
public function testFrom() { $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); } public function testCols() { $select->from('test')->cols(array('col_a', 'col_b')); $this->assertEquals('SELECT col_a, col_b FROM test', $select->__toString()); }
}
![Page 153: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/153.jpg)
DbSelectTest.php
利用 setUp 方法來初始化 fixture
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ protected $_select; protected function setUp() { $this->_select = new DbSelect(); } public function testFrom() { $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); } public function testCols() { $select->from('test')->cols(array('col_a', 'col_b')); $this->assertEquals('SELECT col_a, col_b FROM test', $select->__toString()); }
}
![Page 154: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/154.jpg)
DbSelectTest.php
每一次測試完成後用 tearDown 消滅 fixture
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ protected $_select; protected function setUp() { $this->_select = new DbSelect(); } public function testFrom() { $select->from('test'); $this->assertEquals('SELECT * FROM test', $select->__toString()); } public function testCols() { $select->from('test')->cols(array('col_a', 'col_b')); $this->assertEquals('SELECT col_a, col_b FROM test', $select->__toString()); } protected function tearDown() { $this->_select = null; }}
![Page 155: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/155.jpg)
DbSelectTest.php
$select 改用 $this->_select
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ protected $_select; protected function setUp() { $this->_select = new DbSelect(); } public function testFrom() { $this->_select->from('test'); $this->assertEquals('SELECT * FROM test', $this->_select->__toString()); } public function testCols() { $this->_select->from('test')->cols(array('col_a', 'col_b')); $this->assertEquals('SELECT col_a, col_b FROM test', $this->_select->__toString()); } protected function tearDown() { $this->_select = null; }}
![Page 156: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/156.jpg)
setUp() → testFrom() → tearDown()
setUp() → testCols() → tearDown()
![Page 157: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/157.jpg)
執行測試# phpunit tests/library/DbSelectTestPHPUnit 3.5.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 5.25Mb
OK (2 test, 2 assertions)
這時 DbSelectTest 變成被測試的對象
![Page 158: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/158.jpg)
測試也需要重構
測試與被測試的角色對調
![Page 159: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/159.jpg)
“Houston, we have a problem.”
![Page 160: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/160.jpg)
DbSelect
被用戶發現有 bug
![Page 161: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/161.jpg)
我們預期的用法
假設我們也完成了 where 方法
可以產生條件式
$select = new DbSelect();$select->from('table')->where('id = 1');
![Page 162: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/162.jpg)
我們預期的用法$select = new DbSelect();$select->from('table')->where('id = 1');
// 輸出:// SELECT * FROM table WHERE id = 1
![Page 163: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/163.jpg)
用戶的寫法$select = new DbSelect();$select->from('table WHERE id = 1');
// 輸出:// SELECT * FROM table WHERE id = 1
但用戶卻發現這樣寫也可以
![Page 164: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/164.jpg)
寫程式的人是我
寫出 Bug 的是別的什麼東西
![Page 165: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/165.jpg)
把用戶遇到的問題加入測試
![Page 166: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/166.jpg)
DbSelectTest.php
回到 DbSelectTest.php
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ // ... 略 ...
}
![Page 167: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/167.jpg)
DbSelectTest.php
加入不合法資料表名稱的測試
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ // ... 略 ...
public function testIllegalTableName() { try { $this->_select->from('test WHERE id = 1'); } catch (IllegalNameException $e) { throw $e; } }}
![Page 168: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/168.jpg)
DbSelectTest.php
透過 PHPUnit 的 @expectedException
annotation 來驗證
<?phprequire_once dirname(dirname(__DIR__)) . '/library/DbSelect.php';class DbSelectTest extends PHPUnit_Framework_TestCase{ // ... 略 ...
/** * @expectedException IllegalNameException */ public function testIllegalTableName() { try { $this->_select->from('test WHERE id = 1'); } catch (IllegalNameException $e) { throw $e; } }}
![Page 169: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/169.jpg)
執行測試# phpunit tests/library/DbSelectTestPHPUnit 3.5.15 by Sebastian Bergmann.
.F.
Time: 0 seconds, Memory: 6.00Mb
There was 1 failure:
1) DbSelectTest::testIllegalTableNameExpected exception IllegalNameException
FAILURES!Tests: 3, Assertions: 3, Failures: 1.
應該丟出 IllegalNameException
卻沒有
![Page 170: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/170.jpg)
有時候你需要測試出
預期會錯誤的狀況
![Page 171: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/171.jpg)
DbSelectTest.php
切換到 DbSelect.php<?phpclass DbSelect{ // ... 略 ...
public function from($table) { if (!preg_match('/[0-9a-z]+/i', $table)) { throw new Exception('Illegal Table Name: ' . $table); } $this->_table = $table; return $this; }
// ... 略 ...}
![Page 172: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/172.jpg)
DbSelectTest.php
問題出在這裡
<?phpclass DbSelect{ // ... 略 ...
public function from($table) { if (!preg_match('/[0-9a-z]+/i', $table)) { throw new Exception('Illegal Table Name: ' . $table); } $this->_table = $table; return $this; }
// ... 略 ...}
![Page 173: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/173.jpg)
DbSelectTest.php
前後分別少了 ^ 及 $
<?phpclass DbSelect{ // ... 略 ...
public function from($table) { if (!preg_match('/^[0-9a-z]+$/i', $table)) { throw new Exception('Illegal Table Name: ' . $table); } $this->_table = $table; return $this; }
// ... 略 ...}
![Page 174: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/174.jpg)
執行測試# phpunit tests/library/DbSelectTestPHPUnit 3.5.15 by Sebastian Bergmann.
...
Time: 1 second, Memory: 5.50Mb
OK (3 tests, 3 assertions)
成功!
![Page 175: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/175.jpg)
花一整天找 bug
不如花一小時寫測試
![Page 176: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/176.jpg)
其他常用技巧
![Page 177: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/177.jpg)
如果有多個類別要測試
以前我會用 Test Suite
![Page 178: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/178.jpg)
現在直接測試
tests 資料夾就可以phpunit tests
![Page 179: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/179.jpg)
我們希望控制
執行測試時輸出的結果
![Page 180: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/180.jpg)
交給 phpunit.xml 吧
![Page 181: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/181.jpg)
project
├── application
├── library
└── tests
└── phpunit.xml
範例專案目錄結構
把 phpunit.xml 放在 tests 目錄下
![Page 182: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/182.jpg)
phpunit.xml
root tag 為 phpunit<phpunit>
</phpunit>
![Page 183: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/183.jpg)
phpunit.xml
可以在 root tag 加上測試的設定
<phpunit colors=”true”>
</phpunit>
![Page 184: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/184.jpg)
phpunit.xml
加上多個 test suites<phpunit colors=”true”> <testsuite name="Application Test Suite"> <directory>./application</directory> </testsuite> <testsuite name="Library Test Suite"> <directory>./library</directory> </testsuite></phpunit>
![Page 185: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/185.jpg)
以 phpunit.xml 做測試# phpunit -c tests/phpunit.xml PHPUnit 3.5.15 by Sebastian Bergmann.
....
Time: 0 seconds, Memory: 6.00Mb
OK (4 tests, 4 assertions) 因為 colors=”true” 所以會有顏色
![Page 186: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/186.jpg)
phpunit.xml
也可以在執行測試前預先執行 PHP 程式
例如定義類別自動載入程式
<phpunit colors=”true” bootstrap=”./bootstrap.php”> <testsuite name="Application Test Suite"> <directory>./application</directory> </testsuite> <testsuite name="Library Test Suite"> <directory>./library</directory> </testsuite></phpunit>
![Page 187: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/187.jpg)
bootstrap.php 範例<?phpdefine('PROJECT_PATH', realpath(dirname(__DIR__)));
set_include_path(implode(PATH_SEPARATOR, array( realpath(PROJECT_PATH . '/library'), realpath(PROJECT_PATH . '/application'), get_include_path())));
function autoload($className){ $className = str_replace('_', '/', $className); require_once "$className.php";}
spl_autoload_register('autoload');
![Page 189: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/189.jpg)
最後分享一些小心得
![Page 190: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/190.jpg)
切割你的程式
讓它易於測試
![Page 191: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/191.jpg)
要寫測試不難
難在測試什麼
![Page 192: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/192.jpg)
不要去盲目的信任
要做到反覆的驗證
![Page 193: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/193.jpg)
學會基礎其實不難
變成習慣比較困難
![Page 194: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/194.jpg)
這份 Slides
還有很多東西沒提
![Page 195: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/195.jpg)
只能期待下次再相逢
![Page 196: Beginning PHPUnit](https://reader034.fdocuments.us/reader034/viewer/2022052410/55580efcd8b42a5e468b4771/html5/thumbnails/196.jpg)
謝謝大家