如何使用 Laravel 的 Mailable 测试电子邮件的主题

Fra*_*eto 4 unit-testing mocking laravel-5 laravel-testing

我想知道,是否有一种简单直接的方法可以使用 Laravel 的新 Mailable 功能来测试电子邮件的主题

我有一个类可以发送 5 封不同的电子邮件,但它们都发送给同一个人,因此测试电子邮件是否发送给具体的人并不是真正的完整测试。我需要知道是否向具体的人发送了具体的电子邮件。

我认为,使用电子邮件的主题来测试唯一性是最好的方法。如果你有更好的方法请告诉我。

我有这个:

Mail::assertSentTo([Config::get('mail.backend')], SendEmail::class);

我想添加这样的东西

邮件:: assertSubject ('我的主题', SendEmail::class);

有没有办法做到这一点??

谢谢!

小智 8

编辑

感谢@haakym,在How to make assertions on a Laravel Mailable 上找到了比我的更快更好的解决方案

只需build()在断言之前调用该方法:

Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
            $mail->build();
            return $mail->subject = 'The SUBJECT that I very much need';
        });
Run Code Online (Sandbox Code Playgroud)

无论如何我还是喜欢

Mail::assertSent(InfoRequestMailable::class, function ($mail) {
    $mail->build();
    $this->assertEquals(env('MOREINFO_MAILBOX'), $mail->to[0]['address'], 'The message wasn\'t send to the right email');
    $this->assertEquals('Quite a subject', $mail->subject, 'The subject was not the right one');
    return true;
});

Run Code Online (Sandbox Code Playgroud)

我的原帖

我看到这个问题已经存在一段时间了,但我偶然发现了同样的事情。

重要的是:所有这些都是为了测试一封邮件)。

使用 Laravel 5.6

关于模拟邮件文档中,您可以看到:

use Illuminate\Support\Facades\Mail;

class ExampleTest extends TestCase
{
    public function testOrderShipping()
    {
        Mail::fake();

        // Perform order shipping...

        // Assert a message was sent to the given users...
        Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
            return $mail->hasTo($user->email) &&
                   $mail->hasCc('...') &&
                   $mail->hasBcc('...');
        });

    }
}
Run Code Online (Sandbox Code Playgroud)

这将减轻任何解决方案,对吗?您应该能够执行以下操作:


Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
            return $mail->subject = 'The SUBJECT that I very much need';
        });
Run Code Online (Sandbox Code Playgroud)

这应该有效。对?好吧,除非你做一些不同的事情,否则它不会。

IMO 问题的根源

在邮件指南中,他们展示的每个示例都使用了以下build方法:

public function build()
{
    return $this->from('example@example.com')
                ->subject('The SUBJECT that I very much need')
                ->view('emails.orders.shipped');
}
Run Code Online (Sandbox Code Playgroud)

问题是,当您Mail::fake()在方法的顶部调用时,您会将整个邮件系统变成Illuminate\Support\Testing\Fakes\MailFake(这就是它支持该assertSent方法的原因),这意味着自定义build函数永远不会得到叫。

解决方案

您应该开始更多地使用__constructorMailable 类上的方法。只需返回build()方法中的实例:

遵循(并修改)邮件指南中视图示例

namespace App\Mail;

use Illuminate\Mail\Mailable;

class OrderShipped extends Mailable
{
    ...

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(Order $order)
    {
        $this->order = $order;
        $this->view('emails.orders.shipped');
        $this->subject('The SUBJECT that I very much need');
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this;
    }
}

Run Code Online (Sandbox Code Playgroud)

话虽如此,现在这有效:

Mail::fake();
...
Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
            return $mail->subject == 'The SUBJECT that I very much need';
        });
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

我宁愿做这样的事情,因为我觉得控制更加精细:

class MailControllerTest extends oTestCase
{
    public function testMoreInfo()
    {
        Mail::fake();

        // send the mail

        Mail::assertSent(InfoRequestMailable::class, function ($mail) {
            $this->assertEquals(env('MOREINFO_MAILBOX'), $mail->to[0]['address'], 'The message wasn\'t send to the right email');
            $this->assertEquals('Quite a subject', $mail->subject, 'The subject was not the right one');
            return true;
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

assert单元测试的工作方式永远不会出现错误的情况。:)