PHPUnit 是一個單元測試框架,由 Sebastian Bergmann 所開發。
安裝
有幾種方式可以安裝 PHPUnit
- Pear
- Composer
- PHAR
可以自由選擇你希望的方式來安裝,不過在本書中會大量利用 Laravel 以及 Composer ,會使用最簡單的途徑,在 Laravel 透過 composer.json 來進行安裝 PHPUnit
什麼是 Composer 呢?Composer 是一個 PHP 的套件管理工具,作為 Laravel 開發人員之前,需要基本了解 Composer 是什麼以及如何使用它
在深入了解 Laravel 之前,讓我們從最基礎開始
建立一個新的資料夾練習,在資料夾裡新增一個 composer.json 的檔案並加入以下
|
|
注意我們並沒有加到 require 中,PHPUnit 只有在開發過程中所需要,我們不需要擔心會在正式服務器上。
下一步是安裝以及任何其它依賴的套件,使用 command line
假設已將 Composer 進行 global 安裝
|
|
如果一切順利安裝,你可以查看 vendor/bin/phpunit 、 vendor/phpunit ,試試查詢 PHPUnit 的命令列表
|
|
Global 安裝
在前一章節使用的方法是需要在每一個項目下透過 Composer 進行安裝 PHPUnit,你也可以將 PHPUnit 做 Global 安裝。
在你的 Home 目錄(或任何地方)建立一個新的資料夾,在資料夾裡新增一個 composer.json 的檔案加入你希望 Global require-dev 的套件並安裝
|
|
接下來將這個資料夾下 vendor/bin 的完整路徑加入到 ~/.bash_profile 或 ~/.zshrc (有使用 oh-my-zsh)
|
|
透過這個方式,PHPUnit 就可以在任何地方所呼叫
使用 Composer Global 指令
前面需要手動建立資料夾、composer.json ,Composer 有提供 global 安裝的方式
|
|
安裝完會在 Home 目錄下建立 .composer 的資料夾,並在 ~/.bash_profile 或 ~/.zshrc (有使用 oh-my-zsh)加入以下
|
|
Assertions 101
開始來測試 “hello world”,在這章節,將介紹你第一個 PHPunit assertion,assertTrue
在你的專案下建立 tests 資料夾,並在資料夾下建立一個新檔叫 PracticeTest.php
|
|
執行測試來看它是否可以正常運行
因為我們還沒配置任何設定,所以必需指定一個路徑來進行測試,PHPUnit 會在指定的路徑下尋找測試檔案。
首先,請注意最後一行
這表示一個測試成功了,如果測試失敗,你會看到大寫 F
你將會時常看到測試失敗,所以要去適應它,幸運的是,這個失敗顯示被證明是非常有用的。
以上我們可以看到一個 testHellowWorld 測試失敗,並且是在第八行。
為什麼會有顏色?在下一章會更深入介紹 PHPUnit 的配置選項,在那之前,使用 –colors 就會有顏色顯示
|
|
解析一個 Test Class 的結構
僅管這是一個簡單的 Class,但有幾個重要並要注意的地方,以下又是一個測試程式
|
|
- File Naming:檔名是很重要的,注意我們要跟著 FooTest.php 的規範,雖然這是可以修改的
- Matching:Class 名稱要與檔名一致
- Inheritance:Class 要繼承 PHPUnit_Framework_TestCase,這個 Class 在使用 PHPUnit 時可用,不過,很快可以發現,在 Laravel 的測試中,會是繼承 TestCase ,如果往上查,你會發現父類別確實繼承了 PHPUnit_Framework_TestCase 。
- Method Naming:每一個 Method 名稱應該都描述著這個測試在測什麼,並以 test 為開頭
assertTure
|
|
希望你會發現 PHPUnit 的 test assertions 相當有可讀性,即使不了解具體細節,也很容易知道在做什麼,所有的 assertions 在 test class 都可使用,在這個例子,我們希望 $greeting 等於 “Hello, World.”
這個 assertTure method 接受兩個參數
|
|
你會發現在 PHPUnit 裡,反向 methods 幾乎可以用,如果你要 assert 這個值為 false,那你可以使用 assertFalse
|
|
assertEquals
在前面的例子中,我們唯一的目標是 assert 一個變數一直等於指定的字串,雖然 assertTrue 可以使用,但在這種情況下,它不是一個最佳可讀的方式,不要忽略測試的可讀性。
這種介紹另一個更適合這個例子的 assertion:assertEquals
|
|
這樣可讀性更好,與大多數的 PHPUnit assertions 一樣,assertEquals 接受三個參數
|
|
assertNotEquals 是一個反向 assertion,並接受相同的參數
如果你想證明兩個值是相等的,那麼明顯的使用 assertEquals 比 assertTrue 更好的選擇,即使兩個都可以使用。
assertSame
assertEquals 在需要更嚴格的相等比較時會失敗,例如 assert 變數等於 0?
你可以嘗試:
|
|
這樣是可以通過測試,但如果讓變數為 null ,這個測試還是會通過測試
|
|
這這種情況下,當你需要更嚴格的比較(或有效的 ===),那 assertSame 可以做到
|
|
|
|
assertContains
本書的目的不是教每個 assertion ,但重要的是覆蓋到要點,雖然 PHPUnit 提供了幾十個 assertions ,但你可能會發現,少數幾個就能滿足大多數的測試需求。
假設你有一個名字列表,需要証明該陣列包含一個特定的值,assertTrue 可以處理這個任務,但最好選擇更有可讀性的選項:assertContains 。
|
|
assertContains 的參數值是:
|
|
正如你所知道的,反向 assertion 也是可用的
|
|
assertArrayHasKey
有時你需要 assert 陣列裡的 key,而不是 value
|
|
在這個例子中,假設我們需要驗證 $family 裡有包含 “parents”,在這樣的情況下, assertContains 不是正確的選擇
|
|
我們所需要 assert 指定陣列中的一個 key 值,解決方案是 assertArrayHasKey 。
|
|
assertInternalType
assertInternalType 用來測試變數的型態
|
|
繼續上一個例子,要 assert 這個 $family 裡 parents 為字串或陣列,我們可以這樣做
|
|
|
|
或是要 assert 的型態是整數
|
|
assertInstanceOf
時常你需要確保變數值是某個 Class 的 Instance(實體),這在 PHPUnit 中透過 assertInstanceOf 很容易做到
|
|
範例
|
|
要確保 $stamp 是 PHP DateTime Class 的 Instance ,我們可以使用以下測試方式
|
|
Asserting Exceptions
在單元測試時,重要的是測試你的程式碼中每一個可能的路徑,如果使用太多條件,會讓一個 Class 或 Method 難以測試。
這樣的例子中可能會拋出一個異常,在 PHPUnit 我們使用 doc-blocks 來 assert exceptions .
|
|
這個 doc-blocks 宣告 PHPUnit 應該期望拋出異常,如果沒有,那麼測試就會失敗。
假設一個 Method 如果非數字值傳入應該拋出異常
|
|
請注意,這種情況下,沒有使用 assert ,我們只是加上必要的程式碼,讓這個 Class 發生異常。
總結
雖然可以繼續介面每個 PHPUnit assertion ,但這是不明智的,本章涵蓋少數的 assertions 應該足夠你進行測試了,當你還需要其它功能時,再去查詢文件即可。
接下來在我們開始進行 Laravel 特定的測試之前,我們應該花一些時間來更全面的設定 PHPUnit 配置來滿足我們的需求