1

より良い単体テストなどのためにコードを書くための最良の方法を見つけようとしています。現在、私には2つの主な懸念事項があります。

  1. クラスメソッド内で必要なサービスを取得するためにサービスコンテナを使用しています。最初に準備ができているサービスに依存しているため、これが最善の方法ではない可能性があることを懸念しています
  2. また、モジュール/プラグイン全体で多くの設定にアクセスできるメインの「設定」クラスも使用します。また、これにより、この設定に不要な依存関係が生じることも懸念されます

私の問題を明確にするためのサンプルコード:

class ABC
{
    function someFunction(){
        if(Container::get('settings')->get('status'))
        {
            Container::get('mailer')->send();
        }
    }
}

おそらく、最初にコンストラクターメソッドを介してこれらを注入するだけでよいでしょうか?

4

2 に答える 2

0

サービス コンテナーは、サービス ロケーターのアンチパターンのように見えます。サービス ロケーター自体が役立つ場合はまれですが、テスト可能 (および保守可能) なコードを記述する場合は常に大きな障害になります。

  • グローバル/静的な性質のため、モックするのは (不可能ではないにしても) 困難です。
  • コンポーネントの依存関係を隠すため、コードの読みやすさに影響します
  • 消費者コードとそれ自体の間の密結合を導入します

これらの問題のいくつかは解決できますが、そうする価値はありません。あなたの直感は、コンストラクター注入のような適切な DI パターンにリファクタリングする通常の対処方法であるため、順調に進んでいました。

于 2012-10-16T10:40:55.270 に答える
0

次のようにすることができます:

class ABC
{
    private $_setting = null;
    private $_mailer = null;

    public function setSetting($setting)
    {
        $this->_setting = $setting;
    }

    public function getSetting()
    {
        return $this->_setting;
    }

    public function setMailer($mailer)
    {
        $this->_mailer = $mailer;
    }

    public function getMailer()
    {
        return $this->_mailer;
    }

    function someFunction(){
       if($this->_setting->get('status'))
       {
           $this->_mailer->send();
       }
   }
}

class SettingMock
{
     private $_attributes = array();

     public function setMock($attribute, $value)
     {
         $this->_attributes[$attribute] = $value; 
     }
     public function get($attribute)
     {
         return $this->_attributes[$attribute];
     }

}

class MailerMock
{
    private $_values = array();

    public function setValue($value)
    {
        $this->_values['return'] = $value;
    }

    public function send()
    {
        return $this->_values['return'];
    }
}

テストクラス:

class FooTest extends PHPUnit_Framework_TestCase
{
    public function testSendMail()
    {
         $settingMock = new SettingMock();
         $settingMock->setMock('status', true);

         $mailerMock = new MailerMock();
         $mailerMock->setValue(true);

         $testObject = new ABC();
         $testObject->setSetting($settingMock);
         $testObject->setMailer($mailerMock);

         $return = $testObject->someFunction();
         $this->assertTrue($return);
    }
}
于 2012-10-16T03:49:04.863 に答える