就一般的開發(fā)程序員而言,code過程中調(diào)試、測(cè)試都是必不可少的。受影響于從事C++開發(fā)時(shí)養(yǎng)成的習(xí)慣,調(diào)試呢有斷點(diǎn)調(diào)試,開發(fā)測(cè)試呢有單元測(cè)試。然餓,作為一種Web開發(fā)腳本語(yǔ)言,PHP斷點(diǎn)調(diào)試[看不到變量及堆棧信息]:一堆的var_dump,echo??或者稍有點(diǎn)技術(shù)含量的log_message?更甚至借助第三方工具Xdebug?。。。。。這點(diǎn)我們暫不考慮,此處討論的重點(diǎn)主要圍繞“單元測(cè)試”。
無(wú)論是測(cè)試即有代碼還是為編寫新的代碼,亦或是為重構(gòu)老的代碼做準(zhǔn)備,單元測(cè)試的作用歸根結(jié)底就是保護(hù)。正確的單元測(cè)試就是確保測(cè)試代碼準(zhǔn)確隔離(isolate)了測(cè)試代碼,常見的有TDD,BDD,DDD(領(lǐng)域驅(qū)動(dòng)開發(fā))。
TDD,即測(cè)試驅(qū)動(dòng)開發(fā),是一種利用測(cè)試受益的方法論(或者說實(shí)踐準(zhǔn)則)。簡(jiǎn)單地說,TDD 就是在寫代碼前先寫測(cè)試,并嚴(yán)格遵循red => green => refactor(錯(cuò)誤 => 正確 => 重構(gòu))的流程,所以才叫做“測(cè)試驅(qū)動(dòng)開發(fā)”。一般大致兩種情形是適合的:1.準(zhǔn)備編寫自己覺得“沒譜”的代碼;2.準(zhǔn)備重構(gòu)即有代碼,有可能是改善,也有可能是添加新的功能特性或處理新條件的邏輯,再有就是修復(fù) Bug 等,在這里我都籠統(tǒng)的歸為重構(gòu)。
?Bug 通常都是用戶在使用過程中反饋來(lái)的(我把測(cè)試人員也算在用戶之中),用戶接觸不到更深更內(nèi)在的結(jié)構(gòu),他們都是通過用戶界面來(lái)感受到軟件系統(tǒng)的問題的。此時(shí)最好的入手點(diǎn)當(dāng)然就是重現(xiàn) Bug,而我們剛說過單元測(cè)試覆蓋不了上至用戶界面的層級(jí),所以重現(xiàn) Bug 都是從驗(yàn)收測(cè)試開始的,由此入手一層層抽絲剝繭,經(jīng)歷集成測(cè)試最終定位到單元測(cè)試。這一趟下來(lái)不但 Bug 解決了,而且連帶著把一批復(fù)雜的系統(tǒng)交互都用測(cè)試覆蓋了,這樣用不了多久你就會(huì)發(fā)現(xiàn)該補(bǔ)的測(cè)試也都補(bǔ)的差不多了。
BDD(行為驅(qū)動(dòng)開發(fā),Behaviour Driven Development),比如用戶使用過程中反饋的Bug,自上而下補(bǔ) Bug 測(cè)試。
PHP常見的單元測(cè)試工具可參見:https://codegeekz.com/12-best-php-automated-test-frameworks/,此處我們簡(jiǎn)要介紹phpUnit的簡(jiǎn)單實(shí)用過程。
安裝PHPUnit
訪問phpUnit官網(wǎng)https://phpunit.de/下載相應(yīng)版本的phpUnit,此處我們通過Composer方式安裝:
php -r "readfile('https://getcomposer.org/installer');" | php
composer require --dev phpunit/phpunit ^5.7
編寫PHPUnit測(cè)試
?MVC框架下的controller中新建一個(gè)tests文件夾:
1. 針對(duì)類Class的測(cè)試寫在類ClassTest中; 2. ClassTest(通常)繼承自PHPUnit\Framework\TestCase;3. 測(cè)試都是命令為test*的公用方法,或者在方法的文檔注釋塊中使用@test標(biāo)注將其標(biāo)記為測(cè)試方法;4. 在測(cè)試方法內(nèi),類似于assetEquals()這樣的斷言方法來(lái)對(duì)實(shí)際值與預(yù)期值的匹配做出斷言。比如下圖中phpUnit測(cè)試數(shù)組操作:
PHPUnit支持對(duì)測(cè)試方法間顯式的依賴關(guān)系進(jìn)行聲明,這種依賴關(guān)系并不是定義在測(cè)試方法中的執(zhí)行順序中,而是允許生產(chǎn)者返回一個(gè)測(cè)試基準(zhǔn)(fixture)的實(shí)例,并將此實(shí)例傳遞給依賴關(guān)系。
文檔注釋塊中“用@depends標(biāo)注來(lái)表達(dá)依賴關(guān)系”。比如我們對(duì)上圖中的測(cè)試用例做出分離:
TIPS:默認(rèn)情況下,生產(chǎn)者所產(chǎn)生的返回值將“原樣”傳遞給相應(yīng)的消費(fèi)者,這意味著,如果生產(chǎn)者返回的是一個(gè)對(duì)象,那么傳遞給消費(fèi)者的將是一個(gè)指向此對(duì)象的引用,如果需要傳遞對(duì)象的副本而非引用,則應(yīng)當(dāng)用@depends clone替代@depends。
當(dāng)某個(gè)測(cè)試所依賴的測(cè)試失敗時(shí),PHPUnit會(huì)跳過這個(gè)測(cè)試,通過利用測(cè)試之間的依賴關(guān)系,缺陷定位得到了改進(jìn)。
對(duì)于有多重依賴的測(cè)試【一對(duì)多】,其中第一個(gè)參數(shù)是第一個(gè)生產(chǎn)者提供的基境,第二個(gè)參數(shù)是第二個(gè)生產(chǎn)者提供的基境,以此類推。
數(shù)據(jù)供給器為測(cè)試方法提供參數(shù),文檔注釋塊“@dataProvider additionProvider”,數(shù)據(jù)供給器方法additionProvider必須聲明為public,其返回值要么是一個(gè)數(shù)組,其每個(gè)元素也是數(shù)組;要么是一個(gè)實(shí)現(xiàn)了Iterator接口的對(duì)象,在對(duì)他進(jìn)行迭代時(shí)每一步產(chǎn)生一個(gè)數(shù)組。每個(gè)數(shù)組都是測(cè)試數(shù)據(jù)集的一部分,將以他的內(nèi)容作為參數(shù)來(lái)調(diào)用測(cè)試方法。
對(duì)異常進(jìn)行測(cè)試:/*** @expectedException InvalidArgumentException*/
對(duì)錯(cuò)誤進(jìn)行測(cè)試:/*** @expectedException PHPUnit\Framework\Error*/
命令行測(cè)試執(zhí)行器
PHPUnit 命令行測(cè)試執(zhí)行器可通過 phpunit 命令調(diào)用,phpUnit命令不可用時(shí),以PHP5.6版本為例:
wget https://phar.phpunit.de/phpunit-5.7.phar
chmod +x phpunit-5.7.phar
sudo mv phpunit-5.7.phar /usr/local/bin/phpunit-5.7
phpunit-5.7 --version
phpunit-5.7 --help
組織測(cè)試
PHPUnit 的目標(biāo)之一是測(cè)試應(yīng)當(dāng)可組合:我們希望能將任意數(shù)量的測(cè)試以任意組合方式運(yùn)行,例如,整個(gè)項(xiàng)目的所有測(cè)試,或者項(xiàng)目中的某個(gè)組件內(nèi)的所有類的測(cè)試,又或者僅僅某單個(gè)類的測(cè)試。
PHPUnit 支持好幾種不同的方式來(lái)組織測(cè)試以及將它們編排組合成測(cè)試套件。下面介紹了兩種最常用的方法:
用文件系統(tǒng)來(lái)編排測(cè)試套件
最簡(jiǎn)單的大概就是把所有測(cè)試用例源文件放在一個(gè)測(cè)試目錄中。當(dāng) PHPUnit 命令行測(cè)試執(zhí)行器指向一個(gè)目錄時(shí),它會(huì)在目錄下查找 *Test.php 文通過對(duì)測(cè)試目錄進(jìn)行遞歸遍歷并運(yùn)行測(cè)試。
phpunit --bootstrap src/autoload.php tests
用 XML 配置來(lái)編排測(cè)試套件
測(cè)試替身
轉(zhuǎn)自:https://phpunit.de/manual/current/zh_cn/phpunit-book.pdf
https://www.ibm.com/developerworks/cn/opensource/os-cn-php-autotest/
http://www.thinkphp.cn/topic/37779.html