1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LaravelAdvent Calendar 2022

Day 18

Laravelのメールのテストでの詰まった話

Posted at

はじめに

laravelのメールのテストで、宛先を指定するメールのテストが通らない問題で詰まったので、その話をします。

GETで/mail/sendにアクセスしたら、メールを送信する仕様になっています。
TestMailというMailableクラスを作成して、その中で宛先や件名の設定をしています。

class TestMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($name, $email)
    {
        $this->name = $name;
        $this->email = $email;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->to($this->email)//宛先の指定←ここに注目
            ->subject('テストタイトル')//件名の設定
            ->view('test.mail')
            ->with([
                'name' => $this->name,
            ]);
    }
}

コントローラーは以下の感じです。

class MailController extends Controller
{
    public function send(Request $request)
    {
        $name = 'テスト ユーザー';
        $email = 'test@example.com';

        Mail::send(new TestMail($name, $email));

        return view('welcome');
    }
}

テストを書いてみる

class EmailSendTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    function メールが送られるかのテスト()
    {
        $user = User::factory()->create();

        Mail::fake(); //メールを本当に送らないようにする

        $this->get('/mail/send')
            ->assertOk();

        // メールが送信されたかのテスト(OK)
        Mail::assertSent(TestMail::class);

        // メールが指定の宛先に送信されたかのテスト(テスト落ちてしまう)
        Mail::assertSent(TestMail::class, function ($mail) use ($user) {
            return $mail->hasTo($user->email);
        });
    }
}

問題点

上記のテストをすると以下のようなメールの送信されたかのテストは通りました。

//テスト通る
Mail::assertSent(TestMail::class);

しかし、以下の宛先指定のテストが落ちてしまいました。

//テスト通らない
Mail::assertSent(TestMail::class, function ($mail) use ($user) {
            return $mail->hasTo($user->email);
});

解決方法

試しに以下のように、MailableクラスであるTestMailで宛先を指定しせずに、コントローラーで宛先を指定してみると、、、、

//Mailファサードのtoで宛先を指定するように変更
Mail::to($email)->send(new TestMail($name, $email));

宛先指定のテストが通りました!

//テストが通るようになった!
Mail::assertSent(TestMail::class, function ($mail) use ($user) {
            return $mail->hasTo($user->email);
});

まとめ

この結果から、Mail::assertSentでのテストは、Mailableクラスをテストしているのではなく、
コントローラーで呼ばれた、Mailファサードのテストをしていたことがわかりました。

よって、メールの細かいテスト(件名やbccや宛先など)をしたい時は、Mailableクラスに情報を書くのではなく、Mailファサードに書きましょう。

追記

テストの内で$mail->build()をすると、Mailableクラスで宛先などを指定していても、テストが通りました。

Mail::assertSent(TestMail::class, function ($mail) use ($user) {
            $mail->build();
            return $mail->hasTo($user->email);
        });

ご指摘点や不明点などありましたら教えていただけると幸いです。

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?