unit-testing - 在 CakePHP 中的单元测试期间使用不同的电子邮件配置

标签 unit-testing cakephp phpunit

我在我的一个 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 中检查我们是否在进行单元测试(不知何故?),然后使用“测试”配置。
  • 将我的计算机设置为能够发送电子邮件。

  • 如果我们进行单元测试,我宁愿做第一个但不确定如何在不通过检查膨胀 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/

    相关文章:

    c# - 我可以让 NUnit 以随机顺序执行测试吗?

    C 嵌入式自动单元测试生成

    java - 对 android 库应用程序进行单元测试的最简单方法?

    php - 从android应用程序上传多个图像文件到php服务器

    cakephp - 如何从 cakePHP 的 Controller 内设置分页器页面

    curl - PHPUnit 无法识别 cURL 扩展 - 无法安装 selenium 测试

    php - Laravel 测试服务依赖注入(inject)错误

    javascript - Angular 防止 mock $http 服务

    php - 使用 Containable 时 CakePHP 插件模型不关联

    php - 如何使用 phpunit 测试这个类,它使用到数据库的连接