LoginSignup
9
4

More than 5 years have passed since last update.

CakePHP3 でメール送信をテストする

Last updated at Posted at 2017-11-28

やりたいこと

テストコードで Cake\Mailer\Email::send() で送信したメールを確認したいのです。

環境

  • CakePHP version 3.3.13
  • PHPUnit version 5.7.21

ざっくりした仕組み

CakePHPでは Cake\Mailer\Transport\DebugTransport があり、e-mailのトランスポートにこれを指定します。そうすると、Cake\Mailer\Email::send() の戻り値で送信内容を得られます。

しかし、send() の戻り値を使ってテストコードを書くのは違うので、send()の引数に渡された Cake\Mailer\Email を捕まえてテストできる状態にします。

コード

TestableTransport.php

DebugTransport を継承して、send() の引数を staticなプロパティに貯めておきます。貯めたものは sendMailLst() で取得できます。

tests/Mailer/Transport/TestableTransport.php
namespace App\Test\Mailer\Transport;

use Cake\Mailer\Transport\DebugTransport;
use Cake\Mailer\Email;

/**
 * Class TestableTransport
 * @package Mailer\Transport
 */
class TestableTransport extends DebugTransport
{
    /** @var array 送信したメール */
    private static $mailList = [];

    /**
     * 送信済みメールをリセットします。
     */
    public static function reset()
    {
        static::$mailList = [];
    }

    /**
     *
     * @return array 送信したメールのリスト
     */
    public static function sendMailLst()
    {
        return static::$mailList;
    }

    /**
     * @inheritdoc
     */
    public function send(Email $email)
    {
        static::$mailList[] = clone $email;
        return parent::send($email);
    }

}

phpunit.xml.dist

テストクラスにトラスポートを指定するコードを書くことができますが、環境変数 CAKEPHP_ENV にPHPUnit用のコンフィグレーションを指定します。

phpunit.xml.dist
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
        colors="true"
        processIsolation="false"
        stopOnFailure="false"
        syntaxCheck="false"
        bootstrap="./tests/bootstrap.php"
>
    <php>
        <ini name="memory_limit" value="-1"/>
        <ini name="apc.enable_cli" value="1"/>

        <env name="CAKEPHP_ENV" value="phpunit"/>

    </php>

    <!-- Add any additional test suites you want to run here -->
    <testsuites>
        <testsuite name="App Test Suite">
            <directory>./tests/TestCase</directory>
        </testsuite>
        <!-- Add plugin test suites here. -->
    </testsuites>

    <!-- Setup a listener for fixtures -->
    <listeners>
        <listener
                class="\Cake\TestSuite\Fixture\FixtureInjector"
                file="./vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureInjector.php">
            <arguments>
                <object class="\Cake\TestSuite\Fixture\FixtureManager" />
            </arguments>
        </listener>
    </listeners>

    <!-- Ignore vendor tests in code coverage reports -->
    <filter>
        <whitelist>
            <directory suffix=".php">./src/</directory>
            <directory suffix=".php">./plugins/*/src/</directory>
        </whitelist>
    </filter>
</phpunit>

config/environments/phpunit.php

PHPUnit用のコンフィグレーションで e-mailのトランスポートに TestableTransport を指定します

config/environments/phpunit.php
    'EmailTransport' => [
        'default' => [
            'className' => 'App\Test\Mailer\Transport\TestableTransport',
        ],
    ],

コントローラー

/**
 * メール送信を行うアクション
 */
public function action()
{
// 〜 省略 〜
    $mail = new Email();

    $mail->from('form@example.co.jp');
    $mail->to('to@example.co.jp');
    $mail->subject('mail subject');
    $mail->send('mail message');
// 〜 省略 〜
}

テストコード

Cake\TestSuite\IntegrationTestCase の子クラスでテスト対象のアクションを実行します。

class XXControllerTest extends IntegrationTestCase
{ 
   public function setUp()
    {
        parent::setUp();
        // 送信したメールをリセットする
        TestableTransport::reset();
    }

    public function testMail()
    {
        // メール送信を行うアクションを実行する
        $this->post('/path/to/action', $params);

        // 送信したメールを確認する
        $mails = TestableTransport::sendMailLst();
        $this->assertEquals( 1 , count($mails), '送信したメールが1件だけ存在する');

        /** @var Cake\Mailer\Email $mail */
        $mail = $mails[0];
        $this->assertEquals( ['form@example.co.jp' =>'form@example.co.jp'] , $mail->from(), '差出人');
        $this->assertEquals( ['to@example.co.jp' =>'to@example.co.jp'] , $mail->to(), '送信先');
        $this->assertEquals( 'mail subject' , $mail->subject(), '件名');
        $this->assertEquals( 'mail message', $mail->message(Email::MESSAGE_TEXT), 'メッセージ');
    }
}

9
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4