我在我的一个 Controller 的操作中使用 CakeEmail 类发送电子邮件。在添加电子邮件代码之前,我对该 Controller 进行了单元测试,该测试运行良好。添加电子邮件后,我收到此错误:
SocketException: Could not send email.
这是因为我没有任何方法可以从本地计算机发送电子邮件。
所以我认为在 Config/email.php 中的 EmailConfig 类中有两个不同的配置选项可能是一个好主意(类似于数据库配置文件的工作方式)。默认使用邮件传输,测试使用调试传输。问题在于,与数据库配置不同,Cake 在测试期间不会自动在两者之间切换。
我唯一想到的是在 EmailConfig 类中添加一个构造函数并测试我们是否进行单元测试,但我不确定检查应该是什么。
类似的东西:
class EmailConfig {
public $default = array(
'transport' => 'Mail'
);
public $test = array(
'transport' => 'Debug'
);
public function __construct() {
if ($isUnitTesting) {
$this->default = $this->test;
}
}
}
我上面建议的方法是个好主意吗?如果没有,在单元测试期间,我可以通过哪些其他方式为电子邮件使用不同的传输方式?
更新 - 2012 年 4 月 10 日
我想我以错误的方式解决这个问题。看着 this answer似乎连
$default
默认情况下不加载配置,您必须通过调用 CakeEmail::config()
来指定它方法或在构造函数中给出它。所以我认为这给我留下了两个选择:如果我们进行单元测试,我宁愿做第一个但不确定如何在不通过检查膨胀 Controller Action 的情况下完成此操作,这样做似乎是错误的。
最佳答案
最简单的方法可能是在测试时切换到 DebugTransport。测试的一部分是您需要将程序设计为可测试的。事实上,Cake 中到处都有一些功能就是为了做到这一点。对于您的应用,假设您在用户注册时发送电子邮件:
App::uses('CakeEmail', 'Network/Email');
App::uses('AppController', 'Controller');
class UsersController extends AppController {
public function register() {
//registration logic
$email = new CakeEmail();
$email->from(array('site@example.com' => 'Site'));
$email->to('you@example.com');
$email->subject('Registered');
$email->send('Thanks for registering!');
}
}
这看起来无害,但你不能 mock
CakeEmail
因为它不允许 dependency injection ,这在测试时是必需的。相反,CakeEmail
类应该以允许我们稍后更改它的方式实例化。例如:App::uses('CakeEmail', 'Network/Email');
App::uses('AppController', 'Controller');
class UsersController extends AppController {
public function register() {
//registration logic
$email = $this->_getEmailer();
$email->from(array('site@example.com' => 'Site'));
$email->to('you@example.com');
$email->subject('Registered');
$email->send('Thanks for registering!');
}
public function _getEmailer() {
return new CakeEmail();
}
}
因为我们添加了一个小辅助函数,我们现在可以测试它(通过模拟辅助函数)。
App::uses('CakeEmail', 'Network/Email');
App::uses('UsersController', 'Controller');
class UsersControllerTest extends ControllerTestCase {
public function testRegister() {
$controller = $this->generate('Users', array(
'methods' => array(
'_getEmailer'
)
));
$emailer = new CakeEmail();
$emailer->transport('Debug');
$controller
->expects($this->any())
->method('_getEmailer')
->will($this->returnValue($emailer));
}
}
这个测试为我们的 Controller 创建了一个模拟对象,并告诉它返回我们新创建的
$emailer
对象时 _getEmailer
方法被调用。自 $emailer
已将传输设置为“调试”,可以安全进行测试。当然,因为现在我们正在决定该方法返回的电子邮件对象,模拟
CakeEmail
对象并期望某些返回变得微不足道。
关于unit-testing - 在 CakePHP 中的单元测试期间使用不同的电子邮件配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12712865/