我正在尝试找出编写代码的最佳方法,以便更好地进行单元测试等。目前我有两个主要问题:
- 我
- 使用服务容器在类方法中获取我需要的服务,我担心这可能不是最好的方法,因为我首先依靠这些服务做好准备
- 我还使用一个主要的"设置"类,我可以跨模块/插件访问许多设置。我还担心这会对此设置产生不必要的依赖
一些示例代码来澄清我的问题:
class ABC
{
function someFunction(){
if(Container::get('settings')->get('status'))
{
Container::get('mailer')->send();
}
}
}
也许我应该做的只是先通过构造函数方法注入这些?
你可以做 folow:
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 模式,例如构造函数注入。