用於測試的自動模擬依賴注入
injected Trait
可讓您輕鬆建立類別,並模擬所有依賴項以用於測試目的。
以下模式很常見:
A
並透過建構函式傳入其依賴項(服務物件)A
的每個依賴項的測試,斷言它們按預期調用。許多測試邏輯最終成為建構物件的樣板。 injected Trait
旨在完全刪除這個樣板,讓您專注於重要的事情:測試本身。
使用composer
獲取最新版本(您可能只需要它來進行開發):
$ composer require sellerlabs/ injected --dev
假設我們正在開發一個網頁應用程序,並且我們希望在用戶註冊時向他們發送電子郵件。舉一個簡單的例子,我們假設使用者完全由他們的電子郵件地址定義。當他們註冊時,我們自然會向他們發送一封感謝電子郵件。此外,我們想測試電子郵件是否確實被發送,而不是實際發送。
首先,我們定義一個電子郵件服務:
class EmailService
{
public function email ( $ address , $ content )
{
// Send an email to $address with body $content
}
}
(在真實的應用程式中, email
會發送一封電子郵件——不過,我們不關心這裡的實現!)
我們也定義一個UserController
來處理極為簡單的註冊過程:
class UserController
{
private $ service ;
public function __construct ( EmailService $ service )
{
$ this -> service = $ service ;
}
public function signUp ( $ emailAddress )
{
$ this -> service -> email ( $ emailAddress , ' Thanks for signing up! ' );
return $ emailAddress ;
}
}
在這裡,我們透過建構函數提供EmailService
依賴項,並在我們的(非常簡單的)註冊過程中使用它。
為了測試這個類,我們必須做以下兩件事之一:
Mockery
之類的東西模擬EmailService
對象,並確保使用預期的參數呼叫email
。 injected Trait
可以讓你輕鬆實現選項 2。
use SellerLabs injected injected Trait ;
/**
* Class injected Example
*
* // 1. These are helpful annotations for IDEs and language tools
* @property MockInterface $service
* @method UserController make()
*
* @author Benjamin Kovach <[email protected]>
*/
class injected Example extends PHPUnit_Framework_TestCase
{
// 2. Use our trait
use injected Trait;
// 3. Provide the name of the class to test
protected $ className = UserController::class;
public function testSignUp ()
{
// 4. Make a controller with mocked dependencies
$ controller = $ this -> make ();
$ address = ' [email protected] ' ;
// 5. We can access any mocked dependency of the class as a property
$ this -> service -> shouldReceive ( ' email ' )
-> withArgs (
[
$ address ,
' Thanks for signing up! '
]
);
$ result = $ controller -> signUp ( $ address );
$ this -> assertEquals ( $ address , $ result );
}
}
每個使用injected Trait
類別都需要具有$className
屬性,該屬性用於定位正在測試的類別。 injected Trait
提供了一個公共方法make
,它建構這種類型的對象,但模擬其依賴項並將它們作為屬性保存到測試類別本身。
因此,在testSignUp
中,我們使用make()
建構控制器,這使我們能夠存取名為$service
模擬EmailService
類型物件。這是因為它是在UserController
的建構子中這樣定義的:
public function __construct ( EmailService $ service )
{
$ this -> service = $ service ;
}
在測試案例的持續時間內, $service
成員變數綁定到這個模擬的EmailService
,這使我們能夠對呼叫控制器的signUp
方法時發生的情況做出預期。我們使用Mockery
來建立模擬物件。類別註釋中有一些註釋,有助於 IDE 自動完成這些類,因為模擬屬性是動態聲明的。
這個範例位於tests/ injected Example.php
中。隨意閒逛吧!
此特性的影響可能看起來相對較小,但在處理類別具有多個依賴項的大型應用程式時,這使得測試變得更加容易。