PHPUnit是一個面向PHP程序員的測試框架,這是一個xUnit的體系結構的單元測試框架。
復雜的項目,通過單元測試能夠快速排查bug,有效減少bug的產生。簡單的項目,使用php自帶的var_dump()
、print_r()
也能很方便的調試bug。
PHPUnit通過運行測試用例里的斷言(例如判斷返回結果不為空),檢查代碼是否符合預期。
安裝
安裝方式有兩種。一種是使用phar包,一種是使用Composer。
1、使用phar包
下載地址 https://phpunit.de/
有三個版本:
PHPUnit 6.4 支持PHP 7.0, 和 PHP 7.1。(Current Stable Release)
PHPUnit 5.7 支持 PHP 5.6, PHP 7.0, 和 PHP 7.1。(Old Stable Release)
PHPUnit 4.8 支持PHP 5.3~5.6。(No Longer Supported)
運行方法:
# 通用
php phpunit.phar --version
# linux
chmod +x phpunit.phar
sudo mv phpunit.phar /usr/local/bin/phpunit
phpunit --version
可以查看版本號。
2、使用Composer
如果用 Composer 來管理項目的依賴關系,只要在項目的composer.json 文件中簡單地加上對 phpunit/phpunit
的依賴關系即可。下面是一個最小化的 composer.json
文件的例子,只定義了一個對 PHPUnit 5.7
的開發時依賴:
{
"require-dev": {
"phpunit/phpunit": "5.5.*"
}
}
要通過 Composer
完成系統級的安裝,可以運行:
composer global require "phpunit/phpunit=5.5.*"
請確保 path 變量中包含有 ~/.composer/vendor/bin/
。
配置PhpStorm使用PHPUnit
1、點擊File->Settings->Languages & Frameworks
,點擊php
,設置PHP開發環境:
2、點擊php->PHPUnit
,PHPUnit library
里選中Path to phpunit.phar
,指定路徑,例如:D:\phpsetup\php\phpunit-5.7.4.phar
:
編寫第一個測試用例
1、新建文件夾Testcase
,編寫SayHello.php:
<?php
class SayHello{
public function printHello(){
echo 'Hello';
return 'Hello';
}
}
?>
2、新建測試用例SayHelloTest.php
<?php
require_once 'SayHello.php';
class SayHelloTest extends PHPUnit_Framework_TestCase {
public function setUp(){ }
public function tearDown(){ }
public function testConnectionIsValid(){
$hi = new SayHello();
$this->assertTrue($hi->printHello() == 'Hello');
}
}
編寫完成后,切換到phpunit.phar所在目錄命令行執行:
$ php phpunit.phar Testcase/SayHelloTest.php
輸出結果:
PHPUnit 5.7.4 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)Hello
Time: 130 ms, Memory: 10.00MB
OK (1 test, 1 assertion)
結果表明:
測試通過,1個測試方法,1個斷言,沒有失敗。
這里注意的是:
1、所有以Test結尾的類均為測試用例;
2、所有以test開頭的方法均是測試方法,會自動運行;
3、setUp是每個測試用例最先運行的方法,tearDown是每個測試用例最后運行的方法;
4、assertTrue
用於判斷結果是否為true。
如果用的PhpStorm,可以單擊文件,右鍵Run SayHelloTest
即可看到相同效果;也可以針對整個文件夾全部執行,選擇文件夾Testcase
右鍵Run Testcase
即可。
ThinkPHP3.1集成PHPUnit
集成
需要修改的地方:
1、復制index.php為phpunit.php,內容增加:
define('APP_PHPUNIT', true);
示例:
<?php
define('APP_DEBUG', true);
header("Content-type: text/html; charset=utf-8");
//define('APP_PATH', './');
define('APP_PATH', __DIR__ .'/');
define('APP_PHPUNIT', true);
require APP_PATH .'Core/ThinkPHP.php';
?>
需要使用絕對路徑。
2、修改ThinkPHP/Lib/Core/App.class.php
:
將run()
方法里App::exec()
改為:
(APP_PHPUNIT !== true) && App::exec();//支持phpunit
3、ThinkPHP/Core/Lib/Core/
增加AjaxReturnEvent.class.php
:
<?php
class AjaxReturnEvent extends Exception {
}
4、修改ThinkPHP/Common/runtime.php
:
將2處
CORE_PATH.'Core/Think.class.php',
CORE_PATH.'Core/ThinkException.class.php', // 異常處理類
CORE_PATH.'Core/Behavior.class.php',
改為:
CORE_PATH.'Core/Think.class.php',
CORE_PATH.'Core/ThinkException.class.php', // 異常處理類
CORE_PATH.'Core/Behavior.class.php',
CORE_PATH.'Core/AjaxReturnEvent.class.php',
記得是2處。load_runtime_file和build_runtime_cache方法都要修改。
5、修改ThinkPHP/Lib/Core/Action.class.php
里ajaxReturn方法:
switch (strtoupper($type)){
case 'JSON' :
// 返回JSON數據格式到客戶端 包含狀態信息
header('Content-Type:application/json; charset=utf-8');
if(APP_PHPUNIT === true){throw new AjaxReturnEvent(json_encode($data)); return;}//以支持phpunit捕獲結果
exit(json_encode($data));
case 'XML' :
// 返回xml格式數據
header('Content-Type:text/xml; charset=utf-8');
if(APP_PHPUNIT === true){throw new AjaxReturnEvent(xml_encode($data)); return;}//以支持phpunit捕獲結果
exit(xml_encode($data));
case 'JSONP':
// 返回JSON數據格式到客戶端 包含狀態信息
header('Content-Type:application/json; charset=utf-8');
$handler = isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER');
if(APP_PHPUNIT === true){throw new AjaxReturnEvent($handler.'('.json_encode($data).');'); return;}//以支持phpunit捕獲結果
exit($handler.'('.json_encode($data).');');
case 'EVAL' :
// 返回可執行的js腳本
header('Content-Type:text/html; charset=utf-8');
if(APP_PHPUNIT === true){throw new AjaxReturnEvent($data); return;}//以支持phpunit捕獲結果
exit($data);
default :
// 用於擴展其他返回格式數據
tag('ajax_return',$data);
}
主要做了2件事情:
1、支持phpunit測試模式;
2、防止ajaxReturn里的exit結束了程序。
示例
目錄結構(示例程序采用了模塊分組):
--example
|--Common
|--Conf
|--ThinkPHP
|--Lib
|--Action
| |--Weixin
| |--Api
| |--UserAction.class.php
|--Model
|--Runtime
|--Testcase
|--Weixin
|--Api
|--UserAction.class.php
|--Tpl
|--vendor
|--index.php
|--phpunit.php
1、Model測試
<?php
define('TEST_PATH', dirname(dirname(__FILE__)));
require TEST_PATH .'/../phpunit.php';
class OrderTest extends PHPUnit_Framework_TestCase {
public function testGetBillRule(){
$order_model = D('Orders');
$this->assertTrue(is_object($order_model) == true);
$this->assertNotEmpty($order_model->getBillRule());
}
}
2、Api測試
<?php
define('TEST_APP', 'Api');
define('TEST_PATH', dirname(dirname(__FILE__)));
require TEST_PATH .'/../phpunit.php';
class OrderTest extends PHPUnit_Framework_TestCase {
public function setUp() {
//自動加載
spl_autoload_register (function ( $class ) {
include APP_PATH . 'Lib/Action/'.TEST_APP.'/' . $class . '.class.php' ;
});
}
public function tearDown(){
}
public function testModule(){
$obj = new OrderAction();
$this->assertTrue(is_array($obj->getBillRule()) == true);
}
public function testApi(){
try{
$obj = new OrderAction();
$obj->getBillRule(); //由於TP里的ajaxReturn會使用exit結束程序,這里使用異常來得到返回的內容
}catch(AjaxReturnEvent $e){
$res = json_decode($e->getMessage(), treu);
$this->assertNotEmpty($res);
}
}
}
參考
1、開始使用 PHPUnit – PHP測試框架
http://phpunit.cn/getting-started.html
2、web3d/TPUnit: ThinkPHP PHPUnit框架集成
https://github.com/web3d/TPUnit/
3、[PHP]PHPUnit安裝配置及樣例 | CoinIdea的技術分享博客
http://blog.coinidea.com/web開發/php-1088.html
4、《xUnit Test Patterns》學習筆記系列 - CoderZh - 博客園
http://www.cnblogs.com/coderzh/archive/2010/01/23/xUnit-Test-Patterns.html
(未完待續)