1. 程式人生 > 程式設計 >淺談如何提高PHP程式碼質量之單元測試

淺談如何提高PHP程式碼質量之單元測試

1、單元測試

通過實現單一責任原則(我們的程式碼應該只關注功能的單個部分),我們將確保在測試期間,我們只會同時關注專案的一小部分

通過使用 Liskov 替換原則和依賴倒置原則,我們的程式碼不會關心我們是否www.cppcns.com注入模擬依賴關係,只要它們實現了適當的介面

在單元測試中,我們確實希望用模擬物件替換所有依賴的服務,因此我們一次只測試一個類。但模擬是什麼?它們是實現與其他物件相同的介面的物件,但它們的行為是受控的。例如,假設我們在建立一個價格比較服務,我們利用另一個服務來獲取當前的匯率。在測試我們的比較器時,我們可以使用一個模擬物件來為特定的貨幣返回特定的匯率,因此我們的測試既不依賴也不呼叫真正的服務。

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 介面,該介面被注入到測試物件http://www.cppcns.com的建立中。

你可以看到建立模擬非常容易。你所需要做的就是將它定義為測試函式的引數,並通過指定在執行程式碼時應該執行哪些函式來配置 mock。如果需要,你還可以設定返回值。

所有測試的方法都是從 $this 上下文中執行的,你可以使用與模擬相同的語法來輕鬆地檢查它們的結果。

3、如何設定測試?

Phpspec 有一個很好的文件,但是我將嘗試向你展示一些在日常實踐中有用的基本用例。

構建測試物件

一般來說,設定測試物件的最簡單方法是呼叫 $this->beConstructedWith(…) 方法,該方法將所有應該傳遞給物件建構函式的 params 作為引數。

如果你的物件應該使用工廠方法來建立,那麼你可以使用

this−>beConstructedThrough(this−>beConstructedThrough(methodName,$argumen程式設計客棧tsArray)方法。

在模擬中匹配執行時引數

你會發現 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 === $texnDyIASjVKt;
};
$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,phpspec" />

報告在覆蓋率 / 目錄中生成,作為漂亮的 HTML 頁面,可以瀏覽以檢查測試覆蓋率。

以上就是淺談如何提高PHP程式碼質量之單元測試的詳細內容,更多關於如何提高PHP程式碼質量之單元測試的資料請關注我們其它相關文章!