4

単体テストについて頭を悩ませようとしていますが、見つけなければならないジグソーパズルがもう 1 つあります。

私がやろうとしているのは、次のコードのテストを書くことです。この場合、非常に単純なフロント コントローラー (PHP で記述) を用意しました。

class frontController
{
   public function routeRequest($oRequest)
   {
      $sClassname = $oRequest->getController();
      $sMethod = $oRequest->getAction();

      $oController = new $sClassname();

      $oResponse = $oController->{$sMethod}($oRequest);

      return $oResponse;
   }

}

私が抱えている問題は、コードが新しいオブジェクトを作成するためです。テスト ケース内で実際に何を行うかを厳密に制御できるように、リクエスト オブジェクトを簡単にモックできます。実際にコントローラーをテストダブルに置き換える最善の方法がわかりません。

IBM のこの記事では、コントローラーを作成するためのファクトリー メソッドを用意し、テストに使用する特定のクラスでこれをオーバーライドすることを提案しています。

class frontController
{
   public function routeRequest($oRequest)
   {
      $sMethod = $oRequest->getAction();

      $oController = $this->createController($oRequest);
      $oResponse = $oController->{$sMethod}($oRequest);

      return $oResponse;
   }

   protected function createController($oRequest)
   {
      $sClassname = $oRequest->getController();
      return new $sClassname();
   }

}

そして、おそらく次のようなテストのために:

class testFrontController extends frontController
{
   public function setMockController($oMockController)
   {
      $this->oMc = $oMockController;
   }

   protected function createController($oRequest)
   {
      return $this->oMockController;
   }
}

(これは記事が言っていることとはまったく異なりますが、これができれば私にとって最も役立つと思います)

別の解決策は、コントローラーを作成する別のクラスを持つことです。これは、frontController の依存クラスになります。このようにして、テスト中に factory/creation クラスを test double に置き換えることができます。このようなもの:

class frontController
{
   public function routeRequest($oRequest, $oControllerFactory)
   {
      $sMethod = $oRequest->getAction();

      $oController = $oControllerFactory->create($oRequest);
      $oResponse = $oController->{$sMethod}($oRequest);

      return $oResponse;
   }
}

class controllerFactory
{
   public function create($oRequest)
   {
      $sClassname = $oRequest->getController();
      return new $sClassname();
   }
}

依存性注入は、実際の「ルート」メソッドへのパラメーターではなく、フロントコントローラーコンストラクターまたはセッターを介して処理できると思います。

私はオプション2を好むと思います。

これらの 2 つの方法のどちらかが、この種のものをテストするための正しい方法ですか?

(おそらく、ここでは「良い方法」の方が適切です!)

オプション 1 とオプション 2 についての考えや提案、または実際に代替案を歓迎します。覚えておいてください-重要なことは、実行の一部として他のオブジェクトを作成するオブジェクトをテストする方法です。

ありがとう!

4

4 に答える 4

4

この記事は便利かもしれません。

オブジェクトの作成をアプリケーションの実際の実行から分離する方法について説明します。

于 2009-11-15T07:57:54.160 に答える
2

一般に、このシナリオではファクトリを使用するのが良いと思います。スワップ可能性の側面に加えて、作成されるオブジェクトに必要な追加のパラメーター、データ、または依存関係をファクトリに格納できるため、新しいオブジェクトを実際に要求するオブジェクトはそれらについて何も知る必要がないことを意味します。 ..

于 2009-12-03T05:21:02.690 に答える
0

正確にテストしているものの目標を定義するために、アサーションを熟考したと思います。単体テストは、メソッドからの戻り値をテストすることになることに注意してください。この場合、これは $oResponse (これが何であれ) です。結果として、テスト アサーションはこの戻り値に基づきます。コード スニペットからの戻り値がわからないので、完成できる例を示すことしかできません。

テストにはPHPUnitをお勧めします。これは、PHP imhoの最も完全なパッケージのようです(多くの人はSimpleTestのファンでもあります...それぞれ独自のものです)。

次のようになります (簡潔にするためにインクルードを省略していることに注意してください。詳細については、PHPUnit のドキュメントを参照してください)。

class AimTest extends PHPUnit_Framework_TestCase{
      private $_controller = null;
      private $_request = null;

      public function setUp(){
             $this->_controller = new frontController();
             //what does this object's type?
             $this->_request = new requestObject();  
      }

      public function testObjectCreation(){
            /*
             * note, that this is only one of several assertions that could
             * be made depending on the return value
             */
             $return = $this->_controller->routeRequest($this->_request);
             //tailor to what you expect your output to be
             $this->assertTrue($return == "my expected output");
      }

あなたが述べた目的でマークを完全に見逃していないことを願っています. 話の教訓は、メソッドが返すものだけをテストできるということです。メソッドからオブジェクトのインスタンス化をテストする場合は、インスタンス化後にそのオブジェクトを返すメソッドに対して instanceof PHP 関数を使用します。

于 2009-11-13T14:22:37.627 に答える
0

実際のコントローラーではなく、モックを使用したいと思いませんか?

これを実現する最も簡単な方法は、MockController の名前を返すようにリクエストをサブクラス化することです。

于 2009-11-13T13:18:42.327 に答える