如何提升 PHP 代碼的質量?第二部分 單元測試

在「如何提升 PHP 代碼的質量?」的前一部分中:咱們設置了一些自動化工具來自動檢查咱們的代碼。這頗有幫助,但關於咱們的代碼如何知足業務需求並無給咱們留下任何印象。咱們如今須要建立特定代碼域的測試。php

1 單元測試

最多見的測試軟件的方法多是編寫單元測試。它們的目的是測試代碼的特定單元,基於這樣的假設:一切都按預期運行。爲了可以編寫適當的單元測試,咱們的代碼應該遵循一些基本的設計規則。咱們應該特別關注 SOLID 原則。html

  • 經過實現單一責任原則(咱們的代碼應該只關注功能的單個部分),咱們將確保在測試期間,咱們只會同時關注項目的一小部分
  • 經過使用 Liskov 替換原則和依賴倒置原則,咱們的代碼不會關心咱們是否注入模擬依賴關係,只要它們實現了適當的接口

在單元測試中,咱們確實但願用模擬對象替換全部依賴的服務,所以咱們一次只測試一個類。但模擬是什麼?它們是實現與其餘對象相同的接口的對象,但它們的行爲是受控的。例如,假設咱們在建立一個價格比較服務,咱們利用另外一個服務來獲取當前的匯率。在測試咱們的比較器時,咱們可使用一個模擬對象來爲特定的貨幣返回特定的匯率,所以咱們的測試既不依賴也不調用真正的服務。數組

2 應該使用哪一個框架?

有幾個好的框架能夠達到這個目的。最多見的多是 PHPUnit。在個人工做中,我發現使用行爲方法來編寫測試會帶來更好的結果,並使我更急切地編寫測試。對於咱們的項目,咱們選擇 phpspec。composer

安裝過程至關簡單 - 只需使用:框架

$ 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<?phpnamespace 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);    }}

 

這裏有三個函數:post

  • 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() 的第一個參數是將要調用的方法的名稱,第二個參數是將傳遞給咱們的方法的參數數組。

5 在哪裏能夠找到更多的例子?

在本文中,咱們只介紹了一些基本的用例。請參考 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 代碼的質量?第三:端到端 / 集成測試

相關文章
相關標籤/搜索