Unit testing 在CakePHP中进行单元测试时使用不同的电子邮件配置
在我的一个控制器的操作中,我正在使用CakeEmail类发送电子邮件。我对这个控制器进行了一个单元测试,在添加电子邮件代码之前,该测试运行良好。添加电子邮件后,我收到以下错误: SocketException:无法发送电子邮件 这是因为我没有任何办法从本地机器上发送电子邮件 因此,我认为最好在Config/email.php中的EmailConfig类中有两个不同的配置选项(类似于数据库配置文件的工作方式)。默认设置使用邮件传输,测试使用调试传输。问题在于,与数据库配置不同,Cake在测试期间不会自动在两者之间切换 我唯一想到的是在EmailConfig类中添加一个构造函数,并在进行单元测试时进行测试,但我不确定检查应该是什么 大致如下:Unit testing 在CakePHP中进行单元测试时使用不同的电子邮件配置,unit-testing,cakephp,phpunit,Unit Testing,Cakephp,Phpunit,在我的一个控制器的操作中,我正在使用CakeEmail类发送电子邮件。我对这个控制器进行了一个单元测试,在添加电子邮件代码之前,该测试运行良好。添加电子邮件后,我收到以下错误: SocketException:无法发送电子邮件 这是因为我没有任何办法从本地机器上发送电子邮件 因此,我认为最好在Config/email.php中的EmailConfig类中有两个不同的配置选项(类似于数据库配置文件的工作方式)。默认设置使用邮件传输,测试使用调试传输。问题在于,与数据库配置不同,Cake在测试期间不
class EmailConfig {
public $default = array(
'transport' => 'Mail'
);
public $test = array(
'transport' => 'Debug'
);
public function __construct() {
if ($isUnitTesting) {
$this->default = $this->test;
}
}
}
我上面建议的方法是个好主意吗?如果没有,在单元测试期间,我还可以使用其他什么方式来传输电子邮件
更新-2012年4月10日 我想我走错了方向。现在看来,即使默认情况下没有加载
$default
配置,您也必须通过调用CakeEmail::config()
方法或在构造函数中指定它。所以我认为现在我有两个选择:
我宁愿做第一步,但不确定如何在不检查控制器操作的情况下完成。如果我们正在进行单元测试,那么这样做似乎是错误的。最简单的方法可能是在测试时切换到DebugTransport。测试的一部分是您需要将程序设计为可测试的。事实上,整个蛋糕中到处都有一些功能就是为了实现这一点而设计的。对于您的应用程序,假设您在用户注册时发送电子邮件:
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!');
}
}
这看起来是无害的,但您不能模拟CakeEmail
,因为它不允许,这在测试时是必需的。相反,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();
}
}
因为我们添加了一个小的helper函数,所以现在可以测试它(通过模拟helper函数)
此测试为控制器创建一个模拟对象,并告诉它在调用\u getEmailr
方法时返回新创建的$emailer
对象。由于$emailer
已将传输设置为“调试”,因此测试是安全的
当然,因为现在我们正在决定该方法返回什么电子邮件对象,所以模拟
CakeEmail
对象并期望某些返回变得很简单。只需在测试用例的setUp
中设置配置即可。仅供参考,Cake附带了一个DebugTransport
,您可以在配置设置中使用它,它将执行除实际发送之外的所有操作,并返回标题和消息,供您在测试中使用。超级有用:)你的问题可能比考试更大。电子邮件在现实生活中经常失败;确保代码说明了这一点。我会1)确保成功和不成功的电子邮件都有测试,2)尝试使用模拟CakeEmail对象。不知道你会怎么做#2;否则我会回答。@jeremyharris我确实知道DebugTransport,事实上我正在寻找替代MailTransport的方法。你能详细介绍一下如何在安装程序中设置配置吗?我还没弄清楚它是如何工作的。@BradKoch感谢这里的提示。是的,我确实想到了模拟CakeEmail对象,但我不确定如何在没有任何set*方法的情况下将其传递给控制器。必须考虑一下。是否可以将_getEmailr函数移动到AppController,以便在多个控制器中使用,并且仍然以这种方式工作?@BoštjanPišler是的,只要这些子控制器不以改变其应做工作的方式覆盖_getEmailr()
。(注意:这是一个非常古老的答案,仅适用于蛋糕2.x。)
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));
}
}