[CakePHP] Teste Controller, die „CakeEmail“ verwenden

Seit Version 2.0 des PHP-Frameworks CakePHP ist die Komponente „EmailComponent“ als deprecated gekennzeichnet. Es wird empfohlen die neue Klasse CakeEmail zu verwenden. Die Vorteile sind vorallem in der einfacheren Verwendung zu suchen. Die Konfiguration und die Verwendung der neuen Klasse haben sich auch als äusserst simpel und einfach erwiesen. Erst als es galt, den eben erstellten Controller mit Hilfe eines Unittests zu testen, traten einige Probleme auf.Die CakePHP-Klasse ControllerTestCase, die als Basisklasse für alle Controller-Tests verwendet werden sollte, bietet die Möglichkeit, eine Controller-Klasse mit alle ihren verwendeten Komponenten zu Mocken:

$Users = $this->generate('Users', array(
    'components' => array(
        //'Email',
        'Session'
    )
));

Die Email-Komponente sollte nun aber nicht mehr verwendet werden. Also, funktioniert dieser Ansatz so nicht mehr. Was nun?

Als erstes habe ich in meiner UsersController-Klasse eine protected Membervariable hinzugefügt, die im Konstruktor initialisiert wird:

class UsersController extends AppController
{
    protected $email;

    public function __construct() {
        parent::__construct();
        $this->email = new CakeEmail('gmail');
    }

Wenn die E-Mail-Klasse an vielen Ort verwendet werden soll, kann sie auch direkt in der AppController-Klasse definiert werden (unter ‚app/Controller/AppController.php‘). Der Parameter ‚gmail‘ ist dabei die zu verwendende Konfiguration. Sie befindet sich in der Datei ‚app/Config/email.php‘:

class EmailConfig {
    public $gmail = array(
        'host' => 'ssl://smtp.gmail.com',
        'port' => 465,
        'username' => 'my.name@gmail.com',
        'password' => 'Top$ecret',
        'transport' => 'Smtp'
    );
}

In meinem Test wird nun die Transport-Klasse vor dem Senden eines E-Mails einfach ausgetauscht (Zeile 25 unten), in der Zeile 27 wird die zu testende Action ausgeführt. In diesem Beispiel ist es die Methode ‚register‘ aus dem UsersController. Diese Methode soll einen neuen Benutzer in der Datenbank anlegen und diesem bei Erfolg eine E-Mail schicken, damit die Richtigkeit seiner E-Mail-Adresse überprüft werden kann.

public function testRegisterDataStorable()
{
    $data = array (
        'User' => array (
        'name' => 'Mustermann',
        'forename' => 'Max',
        'email' => 'max@mustermann.net',
        'username' => 'max.m',
        'password' => '1234',
        'password_validate' => '1234'
    ));

    $Users = $this->generate('Users', array(
        'components' => array(
            'Session'
    )));

    $Users->Session
        ->expects($this->once())
        ->method('setFlash')
        ->with($this->isType("string"),
            $this->anything(),
            $this->equalTo(array('class' => 'flash_good')));

    $Users->email->transport('Debug');

    $this->testAction('/users/register', array(
        'data' => $data
    ));

Die DebugTransport-Klasse ist dafür ausgelegt, das Senden von E-Mails zu emulieren, und zu schauen, ob das richtige gesendet worden wäre, ohne allerdings die ganze Zeit sich oder irgendjemandem sonst Test-Mails zu schicken. Im Prinzip also genau das, was bei Unittests passieren soll (häufiges, wiederholtes Ausführen der Tests ist ein Muss mit Unittests!).

Auf jeden Fall kann man im Anschluss auf den Aufruf der Methode ‚testAction‘ auf die Variable email-Variable zugreifen und sich seine Asserts darauf zusammenstellen:

// email headers
$emailHeaders = $Users->email->getHeaders(array('from', 'to', 'subject'));
$this->assertEquals($emailHeaders['To'], 'max@mustermann.net');
...
$vars = $Users->email->viewVars();
$this->assertContains('/users/activate/', $vars['activate_url']);

Voilà, die ganze Sache wird testbar!


Beitrag veröffentlicht

in

, ,

von

Schlagwörter:

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert