Php 这是为了更好地进行单元测试而编写代码的正确方法吗?

Php 这是为了更好地进行单元测试而编写代码的正确方法吗?,php,unit-testing,dependency-injection,Php,Unit Testing,Dependency Injection,我正试图找到最好的方法来编写代码,以便更好地进行单元测试等等。目前我有两个主要问题: 我使用服务容器在类方法中获得我需要的服务,我担心这可能不是最好的方法,因为我依赖于这些服务首先准备好 我还使用了一个主“设置”类,我可以跨模块/插件访问许多设置。我还担心这会对该设置产生不必要的依赖 一些示例代码澄清了我的问题: class ABC { function someFunction(){ if(Container::get('settings')->get('stat

我正试图找到最好的方法来编写代码,以便更好地进行单元测试等等。目前我有两个主要问题:

  • 我使用服务容器在类方法中获得我需要的服务,我担心这可能不是最好的方法,因为我依赖于这些服务首先准备好
  • 我还使用了一个主“设置”类,我可以跨模块/插件访问许多设置。我还担心这会对该设置产生不必要的依赖
  • 一些示例代码澄清了我的问题:

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

    也许我应该首先通过构造函数方法注入这些内容?

    您可以制作以下内容:

    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);
        }
    }
    

    您的服务容器看起来就像它是。虽然服务定位器本身在极少数情况下可能有用,但在编写可测试(和可维护)代码时,它始终是一个主要障碍:

    • 由于其全局/静态特性,很难(如果不是不可能的话)对其进行模拟
    • 它隐藏组件依赖关系,从而影响代码可读性
    • 它引入了消费代码和自身之间的紧密耦合

    虽然其中一些问题可以解决,但不值得这样做。您的直觉是正确的,处理它的通常方法是将其重构为适当的DI模式,如构造函数注入。

    “也许我应该首先通过构造函数方法注入它们?”这是一个使用静态方法的问题。静态方法具有全局范围,很难测试函数/方法。