淺談如何提高PHP代碼質量之單元測試
1、單元測試
通過實現單一責任原則(我們的代碼應該隻關註功能的單個部分),我們將確保在測試期間,我們隻會同時關註項目的一小部分
通過使用 Liskov 替換原則和依賴倒置原則,我們的代碼不會關心我們是否註入模擬依賴關系,隻要它們實現瞭適當的接口
在單元測試中,我們確實希望用模擬對象替換所有依賴的服務,因此我們一次隻測試一個類。但模擬是什麼?它們是實現與其他對象相同的接口的對象,但它們的行為是受控的。例如,假設我們在創建一個價格比較服務,我們利用另一個服務來獲取當前的匯率。在測試我們的比較器時,我們可以使用一個模擬對象來為特定的貨幣返回特定的匯率,因此我們的測試既不依賴也不調用真正的服務。
2、應該使用哪個框架?
有幾個好的框架可以達到這個目的。最常見的可能是 PHPUnit。在我的工作中,我發現使用行為方法來編寫測試會帶來更好的結果,並使我更急切地編寫測試。對於我們的項目,我們選擇 phpspec。
安裝過程相當簡單 – 隻需使用:
$ php composer.phar require –dev phpspec/phpspec
然後,如果你在本文的第一部分中配置瞭 PHing,那麼你可以在 build.xml 中添加構建目標:
<target name="phpspec"> <exec executable="bin/phpspec" passthru="true" checkreturn="true"> <arg line="run --format=pretty" /> </exec> </target>... <target name="run" depends="phpcs,phpcpd,phan,phpspec" />
然後,你必須為你想要測試的每個服務類創建一個測試類。讓 PHPSpec 非常容易使用的是模型創建。你隻需使用嚴格的輸入,就可以將模擬對象聲明為測試函數的參數。PHPSpec 會自動為你創建模擬。讓我們看一下代碼示例:
//spec/Domain/PriceComparatorSpec.php <?php namespace spec\Domain; use Domain\Price;use Domain\PriceConverter; use PhpSpec\ObjectBehavior; class PriceComparatorSpec extends ObjectBehavior{ public function let(PriceConverter $converter) { $this->beConstructedWith($converter); } public function it_should_return_equal() { $price1 = new Price(100, 'EUR'); $price2 = new Price(100, 'EUR'); $this->compare($price1, $price2)->shouldReturn(0); } public function it_should_convert_first(PriceConverter $converter) { $price1 = new Price(100, 'EUR'); $price2 = new Price(100, 'PLN'); $priceConverted = new Price(25, 'EUR'); $converter->convert($price2, 'EUR')->willReturn($priceConverted); $this->compare($price1, $price2)->shouldReturn(1); } }
這裡有三個函數:
- let( ) – 它允許使用依賴來初始化服務
- 兩個 it_* 函數實現測試。其中一種方法是使用模擬 $priceConverter 的方法實現 priceConverter 接口,該接口被註入到測試對象的創建中。
你可以看到創建模擬非常容易。你所需要做的就是將它定義為測試函數的參數,並通過指定在執行代碼時應該運行哪些函數來配置 mock。如果需要,你還可以設置返回值。
所有測試的方法都是從 $this 上下文中運行的,你可以使用與模擬相同的語法來輕松地檢查它們的結果。
3、如何設置測試?
Phpspec 有一個很好的文檔,但是我將嘗試向你展示一些在日常實踐中有用的基本用例。
構建測試對象
一般來說,設置測試對象的最簡單方法是調用 $this->beConstructedWith(…) 方法,該方法將所有應該傳遞給對象構造函數的 params 作為參數。
如果你的對象應該使用工廠方法來創建,那麼你可以使用
this−>beConstructedThrough(this−>beConstructedThrough(methodName,$argumentsArray)方法。
在模擬中匹配運行時參數
你會發現 phpspec 使用一種非常類似於人類的語法來配置模擬。例如,如果你想要檢查在運行時是否有一個模擬方法 someMethod 與參數“desired value”被調用,你可以在測試中定義它,如下面的例子:
$mockObject->someMethod("desired value")->shouldBeCalled();
如果你想要測試代碼的行為,當一些 mock 的函數返回“some value”時,你可以通過調用來輕松地設置它:
$mockObject->someFunction("some input")->willReturn("some value");
有時我們並不真正關心傳遞給 mock 的確切參數。然後可以寫這段代碼:
use Prophecy\Argument\Token\AnyValueToken; $mockObject->someFunction(new AnyValueToken())->willReturn(true);
有時你會關心一些參數,最好是寫一個檢查函數,它會告訴你是否正確地調用瞭一些方法,例如:
use Prophecy\Argument\Token\CallbackToken; $checker = function (Message $message) use ($to, $text) { return $message->to === $to && $message->text === $text; }; $msgSender->send(new CallbackToken($messageChecker))->shouldBeCalled()
匹配運行時異常
。在某些情況下,異常是代碼接口的一部分。你希望它們在特定的場景被拋出。你可以通過編寫以下代碼來完成這項工作:
$this->shouldThrow(\DomainException::class)->during('execute', [$command, $responder]);
傳給 during() 的第一個參數是將要調用的方法的名稱,第二個參數是將傳遞給我們的方法的參數數組。
4、在哪裡可以找到更多的例子?
在本文中,我們隻介紹瞭一些基本的用例。請參考 phpspec 的文檔,以找到更多的示例,這些示例將使你的測試代碼變得漂亮!
代碼覆蓋率
PHPSpec 附帶瞭擴展子系統,它允許例如創建代碼覆蓋率報告。如果您想要檢查在測試中執行瞭多少代碼,它們是很有幫助的。
你可以通過以下來安裝這個擴展:
$ php composer.phar require –dev leanphp/phpspec-code-coverage
然後通過創建 phpspec 來啟用它。yml 文件內容:
1 extensions: LeanPHP\PhpSpec\CodeCoverage\CodeCoverageExtension: ~
默認情況下,這個擴展會使用 PHP 的 Xdebug 擴展生成代碼覆蓋率信息,但是 PHP 的本機調試器 – phpdbg 會更快速一些:
$ phpdbg -qrr phpspec run
現在,你可以在 build 中更改 phpspec 的構建目標。xml:
<target name="phpspec"> <exec executable="phpdbg" passthru="true" checkreturn="true"> <arg line="-qrr bin/phpspec run --format=pretty" /> </exec> </target>... <target name="run" depends="phpcs,phpcpd,phan,phpspec" />
報告在覆蓋率 / 目錄中生成,作為漂亮的 HTML 頁面,可以瀏覽以檢查測試覆蓋率。
以上就是淺談如何提高PHP代碼質量之單元測試的詳細內容,更多關於如何提高PHP代碼質量之單元測試的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 淺談如何提高PHP代碼質量之端到端集成測試
- 基於SpringBoot Mock單元測試詳解
- Mock.js的安裝與使用教程(擺脫後端同學的束縛)
- Python進行區間取值案例講解
- 使用python 進行區間取值的方法