2012-10-03 22 views
5

Enviaré un correo electrónico utilizando la clase CakeEmail en una acción de uno de mis controladores. Tengo una prueba de unidad para este controlador que funcionaba bien antes de agregar el código de correo electrónico. Después de añadir el correo electrónico que sale este error:Use una configuración de correo electrónico diferente durante la prueba de unidad en CakePHP

SocketException: Could not send email.

Esto se debe al hecho de que no tengo ninguna manera de enviar mensajes de correo electrónico de mi máquina local.

Así que pensé que tal vez una buena idea sería tener dos opciones de configuración diferentes dentro de la clase EmailConfig en Config/email.php (Similar a cómo funciona el archivo de configuración de la base de datos). El valor predeterminado con el transporte de correo y una prueba con el transporte de depuración. El problema con esto es que, a diferencia de la configuración de la base de datos, Cake no cambia automáticamente entre los dos durante la prueba.

Lo único que he pensado es agregar un constructor a la clase EmailConfig y probar si estamos realizando pruebas unitarias, pero no estoy seguro de cuál será el control.

Algo a lo largo de las líneas de esto:

class EmailConfig { 

    public $default = array(
     'transport' => 'Mail' 
    ); 

    public $test = array(
     'transport' => 'Debug' 
    ); 

    public function __construct() { 
     if ($isUnitTesting) { 
      $this->default = $this->test; 
     } 
    } 

} 

hubiera hecho mi manera sugerida por encima de ser una buena idea? Si no, ¿de qué otra manera puedo usar un transporte diferente para el correo electrónico durante la prueba unitaria?


Actualización - 4/10/2012

creo que iba de este por el camino equivocado. Si mira this answer parece que incluso la configuración $default no está cargada de manera predeterminada, debe especificarla llamando al método CakeEmail::config() o proporcionándolo en el constructor. Así que creo que esto me deja dos opciones ahora: (? De alguna manera)

  1. en la comprobación de controlador si tenemos pruebas unitarias y luego usar la configuración de 'prueba'.
  2. Configurar mi computadora para poder enviar correos electrónicos.

prefiero hacerlo al principio, pero no está seguro de cómo esto se puede hacer sin inflar la acción del controlador con cheques si tenemos pruebas de unidad, parece incorrecta de hacer esto.

+0

Simplemente configure la configuración en 'setUp' en su caso de prueba. Para tu información, Cake viene con un 'DebugTransport' que puedes usar en tu configuración de configuración que hará todo excepto enviar, y devolverá los encabezados y mensajes para que los uses en tus pruebas. Súper útil :) – jeremyharris

+0

Sus problemas pueden ser más grandes que la prueba. Los correos electrónicos fallan regularmente en la vida real; asegúrese de que el código sea responsable de eso. Yo 1) me aseguraría de que existan pruebas para correos electrónicos exitosos y fallidos y 2) trate de usar un objeto falso de CakeEmail. No estoy seguro de cómo harías para hacer # 2; de lo contrario, respondería. –

+0

@jeremyharris Ya sabía sobre el DebugTransport, de hecho, estaba buscando maneras en que podría ser utilizado en lugar del MailTransport. ¿Sería capaz de ampliar sobre cómo configurar la configuración en la configuración, no pude entender cómo podría funcionar. – Josh

Respuesta

4

La manera más fácil es probablemente cambiar a DebugTransport durante la prueba. Parte de las pruebas es que debe diseñar su programa para que sea comprobable. De hecho, hay algunas funciones aquí y allá en Cake diseñadas para hacer justamente eso. Para su aplicación, vamos a suponer que usted envíe un correo electrónico cuando un usuario se registra:

App::uses('CakeEmail', 'Network/Email'); 
App::uses('AppController', 'Controller'); 

class UsersController extends AppController { 

    public function register() { 
    //registration logic 
    $email = new CakeEmail(); 
    $email->from(array('[email protected]' => 'Site')); 
    $email->to('[email protected]'); 
    $email->subject('Registered'); 
    $email->send('Thanks for registering!'); 
    } 

} 

Esto parece inofensivo, pero no se puede burlarse CakeEmail, ya que no permite dependency injection, que es necesaria durante la prueba. En cambio, la clase CakeEmail se debe instanciar de una manera que nos permita cambiarla más tarde. Por ejemplo:

App::uses('CakeEmail', 'Network/Email'); 
App::uses('AppController', 'Controller'); 

class UsersController extends AppController { 

    public function register() { 
    //registration logic 
    $email = $this->_getEmailer(); 
    $email->from(array('[email protected]' => 'Site')); 
    $email->to('[email protected]'); 
    $email->subject('Registered'); 
    $email->send('Thanks for registering!'); 
    } 

    public function _getEmailer() { 
    return new CakeEmail(); 
    } 

} 

Debido a que hemos añadido un poco de función auxiliar, ahora podemos probar que (al burlarse de la función auxiliar).

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

} 

Esta prueba crea un objeto de burla para nuestro controlador y le indica que debe devolver el recién creado $emailer objeto cuando se llama al método _getEmailer. Como el $emailer ha establecido el transporte en 'Depurar', es seguro para la prueba.

Por supuesto, desde ahora estamos decidiendo qué objeto de correo electrónico devuelve el método, burlarse del objeto CakeEmail y esperar ciertos retornos se vuelve trivial.

+0

¿Puede la función _getEmailer moverse a AppController para ser utilizada en múltiples controladores y seguir funcionando de esta manera? –

+0

@ BoštjanPišler Sí, siempre que esos controladores secundarios no sobrescriban '_getEmailer()' de una manera que cambie lo que debería hacer. (* Nota: esta es una respuesta muy antigua y solo se aplica a Cake 2.x. *) – jeremyharris

Cuestiones relacionadas