目錄php
v1.0
html
做者:ZBW、ZGJlaravel
PHP應用大多應用的單元測試框架是PHPUnit,這一框架也被Laravel集成了進來,而且Laravel增添了一些額外的功能以方便開發者進行Web相關的測試。本文將以項目中應用的單元測試爲基礎,介紹Laravel下PHPUnit的相關內容。web
注意到本文以Laravel 5.1爲基礎,可能部分API在後續版本中有變更,但總體的使用方法變更不大。數據庫
經過composer配置composer.json中的依賴,並使用composer install
來安裝phpunit,安裝後的二進制文件在/vendor/bin/下。json
(也可嘗試使用apt install phpunit
來安裝phpunit)bootstrap
Laravel默認自帶了名爲phpunit.xml
的配置文件,該文件已經爲咱們配置好了phpunit自己。api
項目使用的配置文件以下:數組
<?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" backupStaticAttributes="false" bootstrap="bootstrap/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false"> <testsuites> <testsuite name="Application Test Suite"> <directory>./tests/</directory> </testsuite> </testsuites> <filter> <whitelist> <directory suffix=".php">app/</directory> </whitelist> </filter> <php> <env name="APP_ENV" value="testing"/> <env name="CACHE_DRIVER" value="array"/> <env name="SESSION_DRIVER" value="array"/> <env name="QUEUE_DRIVER" value="sync"/> </php> <logging> <log type="coverage-html" target="./tests/codeCoverage" charset="UTF-8"/> </logging> </phpunit>
其中須要注意如下內容:瀏覽器
<filter>:該部分定義了phpunit可訪問的路徑,以上配置中咱們只測試app文件夾下的內容。
基於以上內容,一個方便瀏覽測試報告的方式是,將tests/codeCoverage文件夾下的報告入口html文檔軟連接至public文件夾下,從而能夠由瀏覽器直接訪問:
ln -s tests/codeCoverage public/tests
從而瀏覽器訪問路由:/tests便可看到測試報告。
規範的方法是使用artisan新建測試樣例:
php artisan make:test xxxTest
該命令會在tests文件夾下新建一個xxxTest.php,其中包含了一個默認測試函數。
在這部份內容中咱們主要須要應用斷言來檢查函數的輸入和輸出是否匹配。斷言是phpunit自己就帶有的功能。
經常使用的一些斷言包括:
$this->assertTrue(表達式) //檢查表達式是否爲真 $this->assertFalse(表達式) //檢查表達式是否爲假 $this->assertEquals(X,Y) //檢查兩個變量是否相等 $this->assertFileExists(文件) //檢查文件是否存在
具體的斷言函數可參考PHPUnit文檔
Laravel集成PHPUnit最方便的地方是其能夠編寫關於Web控制器及功能的測試。
例如測試某個頁面訪問是否正常的測試內容以下:
public function testIndex() { $this->visit('logout') ; $this->visit('/desexp') ->see("設計性實驗") ->see("請選擇實驗") ->see("D01"); $this->visit('/login') ->see('登陸') ->type($this->gen_admin_email , 'email') ->type($this->gen_admin_password , 'password') ->press('login-submit'); $this->visit('/desexp') ->see("設計性實驗") ->see("請選擇實驗") ->see("D01"); }
這部分測試編寫的方式是將全部須要運行的函數按前後順序串聯起來。
一些訪問方面的函數以下,這部分函數通常用於測試訪問及與頁面進行交互。
visit('路由') // 訪問某個地址 see('xxx') //檢查訪問的頁面中是否出現了xxx dontSee('xxx') //與see功能相反,檢查是否沒有出現xxx type('輸入內容',輸入框name屬性) //輸入內容至輸入框 check('單選框name屬性') //選中checkbox select(’內容‘,’下拉菜單區域‘) //選擇下拉菜單項 press('xxx') //按下指定元素或按鈕 attach('文件路徑','文件上傳name屬性') //附加文件
在上文的例子中,咱們測試前能夠選擇手動模擬登錄操做。
測試JSON API時以上的函數每每起不到做用,此時須要使用以下的函數來向接口發起請求及驗證結果。
get/post/put/patch/delete('address',[payloads]) //以以上的HTTP方法請求路由 seeJson([json內容]) //檢查返回的json是否包含內容
固然以前的visit
方法能夠看做沒有額外數據的get
(注意不是無參數,後文會介紹)
一個例子以下,這部分代碼經過getTable函數驗證了獲取html表格內容的正確性。
$_GET['id'] = $this->report_id_pub ; $html_file = Config::get('phylab.experimentViewPath').$this->report_id_pub.".html"; $str_html = file_get_contents($html_file); $this->visit('/getTable') ->seeJson([ 'status' => SUCCESS_MESSAGE , 'contents' => $str_html , ]) ;
此外,還有call('http請求方法','路由',‘數據’...)
這一方法以更靈活的方式向接口發起請求。這一函數將返回Laravel原生的http請求對象。你能夠繼而經過phpunit的斷言驗證其中結果。
Laravel增長了一些額外的斷言以方便用戶檢查Web請求的結果。例如:
->assertResponseOk(); //檢查返回是否爲HTTP 200 ->assertResponseStatus($code); //檢查返回是不是指定的狀態碼 ->assertRedirectedTo($uri, $with = []); //檢查是否有重定向
具體能夠參考PHPUnit Assertions
在Laravel中部分路由經過中間件來確保安全性,例如不少API以Auth中間件來確保只有登錄用戶才能使用接口,但在測試中常常登錄無疑增長了測試的複雜性,使用session相對來講也是一種麻煩的辦法。
能夠在測試類的開頭增長以下內容
use WithoutMiddleware;
從而在該測試代碼文件中暫時使中間件不產生做用
部分測試的函數須要對數據庫進行操做,而測試先後須要保證數據庫狀態的一致性。手動進行恢復的操做也不現實,好在Laravel內置了一些方法使咱們能方便地進行數據庫方面的測試
使用遷移:use DatabaseMigrations;
或使用事務:use DatabaseTransactions;
將以上內容任一個添加在測試類開頭,Laravel會替你完成數據庫在測試先後的恢復工做
在咱們的項目中,以前的開發者在不少地方定義了一些全局變量,或者能夠說是相似於C語言的宏定義。包括Laravel框架自己中也包含了不少這樣的宏定義。初次運行測試時咱們遇到的一個很尷尬的問題是:不能有多個測試代碼文件,不然phpunit就會報相似於」重複定義「的錯誤。
一個暫時的解決辦法是這樣的,在每一個測試類開頭添加:
protected $preserveGlobalState = FALSE; protected $runTestInSeparateProcess = TRUE;
這二者意味着每一個測試進程是獨立的,且各測試之間的狀態不被保留。
前述的一些用於測試的請求方法,其中能夠額外附帶的數組參數其實是請求附帶的payloads,但不少時候咱們要發起相似這樣的帶參數請求:
http://ip:port/getTable?id=1234567
若是直接在get
方法內設置['id'=>'1234567']
,會發現測試運行中仍是直接請求/getTable
,而沒有任何參數
一個解決辦法是測試時直接修改PHP的_GET
變量,例如
$_GET['id'] = '1234567' ;
這一辦法筆者認爲有些簡單粗暴,但還沒找到更好的方法,還請各位讀者多多指教。
運行測試很是簡單,只須要在phpunit.xml所在的目錄下運行:phpunit
,便可自動運行全部測試。
若是你想運行單個測試文件,能夠以以下方式:
phpunit path\to\testFile.php
這將運行該文件中的全部測試函數。
你也能夠運行某一個測試函數,但該狀況下最好指定該函數所在的文件,以免重名的狀況:
phpunit --filter testFunction path\to\testFile.php
在配置部分配置了軟連接後,你能夠直接進入測試報告的頁面
ln -s tests/codeCoverage public/tests
直接訪問ip:port/tests後將自動進入測試報告的主頁,點擊每一個文件夾能夠瀏覽其中內容的測試覆蓋率。
測試覆蓋率分爲三欄,第一欄是覆蓋的行數,第二欄是方法數,第三欄是覆蓋的類的數量。