在開發程式時,為了確保程式的正確性,一定都會使用到單元測試。但撰寫單元測試的方法因人而異,有時候土炮起來寫測試程式的時間還比正常開發的時間還要長,這時候就必須找個適合的工具幫忙處理測試的問題。PHPUnit就是負責解決這樣的狀況。
安裝 (可參考 安裝文件)
wget https://phar.phpunit.de/phpunit.phar chmod +x phpunit.phar mv phpunit.phar /usr/local/bin/phpunit
PS:為了避免程式找不到PHPUnit的class,最好是用PHP的get_include_path()檢查path是不是有引入PEAR的路徑(如果沒有可以到php.ini新增)
撰寫 PHPUnit 測試程式
首先建立一個簡單的程式,負責加總傳入的n到m總合
Math.php
class Math { function sum($min, $max){ $total = 0; for($i = $min; $i <= $max; $i++){ $total += $i; } return $total; } }
接著撰寫PHPUnit測試程式
MathTest.php
//引入要測試的程式 require "Math.php"; class MathTest extends PHPUnit_Framework_TestCase { //測試function的命名為test + function name public function testsum() { //assertEquals為判斷值是否相同,55為正確的結果,比對傳入sum(1,10)時,是否傳出55 $this -> assertEquals(55,Math::sum(1,10)); $this -> assertEquals(5050,Math::sum(1,100)); } }
寫好測試程式之後,就可以透過指令測試
phpunit MathTest.php #如果正確的話,應該會輸出OK (1 test, 2 assertion),代表一組測試二筆測資
Data Provider
上面的例子也可以改成以 Data Provider的方式餵資料進去,這樣一來就不必寫很多次assertEquals
MathTest.php
//引入要測試的程式 require "Math.php"; class MathTest extends PHPUnit_Framework_TestCase { //利用PHPUnit @dataProvider annotation來引用自訂的DataProvider /** * @dataProvider sumDataProvider */ public function testsum($expected, $min, $max) { $this -> assertEquals($expected,Math::sum($min,$max)); } public function sumDataProvider(){ return array( array(55,1,10), array(5050,1,100), ); } }
PS:Data Provider提供的資料都會被當成一組test,所以測試後應該會出現OK (2 tests, 2 assertions)
setUP、tearDown
setUP和tearDown是執行PHPUnit時預設執行的函式,主要是用來初始化設定及結束設定用的,執行順序為:setUp、test*、tearDown
MathTest.php
require "Math.php"; class MathTest extends PHPUnit_Framework_TestCase { protected $_object; protected function setUp(){ //開始測試時產生物件 $this -> _object = new Math(); } /** * @dataProvider sumDataProvider */ public function testsum($expected, $min, $max) { $this -> assertEquals($expected,$this -> _object -> sum($min,$max)); } public function sumDataProvider(){ return array( array(55,1,10), array(5050,1,100), ); } protected function tearDown(){ //測試結束時結束物件 $this -> _object = null; } }
上面的範例執行順序為:1.setUp、testsum(55,1,10)、tearDown 2.setUp、testsum(5050,1,100)、tearDown
測試錯誤:expectedException
在某些時候必須去測試錯誤,因為當使用者輸入錯的資料時,程式沒有噴出Exception,這樣的程式也是有問題的,PHPUnit可以透expectedException annotation 來測試預期的錯誤(要傳出正確的Exception才算測試成功)
ExceptionTest.php
class ExceptionTest extends PHPUnit_Framework_TestCase{ /** * @expectedException BadFunctionCallException */ public function testException(){ try { //dosomething } catch(BadFunctionCallException $e){ throw $e; } } }
套件測試:Suite
若一個專案有多個測試時,可以透過Suite將所有測試程式包成套件測試
AllTest.php
require "ExceptionTest.php"; require "MathTest.php"; class AllTest extends PHPUnit_Framework_TestCase { public static function suite(){ $suite = new PHPUnit_Framework_TestSuite('SuiteName'); //加入class名稱 $suite -> addTestSuite('ExceptionTest'); $suite -> addTestSuite('MathTest'); return $suite; } }
也可以將多個套件再包裝成一組套件
All2Test.php
require "AllTest.php"; class All2Test extends PHPUnit_Framework_TestCase { public static function suite(){ $suite = new PHPUnit_Framework_TestSuite('SuiteName'); //加入套件 $suite -> addTest(AllTest::suite()); return $suite; } }
phpunit.xml
除了使用程式包裝成套件之外,也可以透過phpunit.xml來完成
phpunit.xml
<!-- colors為true可以讓測試結果加上顏色方塊,bootstrap可以自行定義init程式(例如define一些變數) --> <phpunit colors="true" bootstrap="init.php"> <testsuite name="TestSuite"> <directory>./tests</directory> </testsuite> </phpunit>
測試
#使用phpunit指令,預設會按照phpunit.xml執行 phpunit #指定執行其他檔名的xml phpunit -c xxx.xml #也可以在phpunit.xml同一層目錄下直接使用資料夾名稱 phpunit <directory>
另外要注意,phpunit.xml的目錄是判斷 xxxTest的程式才會執行,所以命名時要特別注意一下
相關資料可以參考 PHPUnit文件