テスト用の自動モック依存関係注入
injected Trait
と、テスト目的ですべての依存関係をモックアウトしたクラスを簡単に作成できます。
次のパターンは非常に一般的です。
A
を作成します。A
の各依存関係を模擬するテストを作成し、それらが期待どおりに呼び出されることを主張します。テスト ロジックの多くは、最終的にはオブジェクトを構築するための定型的なものになります。 injected Trait
このボイラープレートを完全に削除し、重要なこと、つまりテスト自体に集中できるようにすることを目的としています。
最新リリースを取得するには、 composer
を使用します (おそらく、開発にのみ必要になります)。
$ composer require sellerlabs/ injected --dev
Web アプリを開発していて、ユーザーがサインアップしたときにユーザーにメールを送信したいとします。簡単な例として、ユーザーが完全に電子メール アドレスによって定義されていると仮定しましょう。彼らがサインアップしたら、当然のことながら、お礼のメールを送りたいと考えます。さらに、電子メールを実際に送信せずに、実際に送信されるかどうかをテストしたいと考えています。
まず、電子メール サービスを定義しましょう。
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
依存関係を提供し、(信じられないほど単純な) サインアップ プロセス中にそれを使用します。
このクラスをテストするには、次の 2 つのうちの 1 つを行う必要があります。
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
にあります。気軽に覗いてみてください!
この特性の影響は比較的小さいように思えるかもしれませんが、クラスにいくつかの依存関係がある大規模なアプリケーションで作業する場合、これによりテストがはるかに簡単になります。