How to make assertions on a Laravel Mailable

馋奶兔 提交于 2020-01-05 05:09:27

问题


In a test I would like to make some assertions on a Mailable using Mail::assertSent(), like this:

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

So far, I have found the hasTo(), hasFrom(), hasBcc() and all the other has*() methods work just great. However, when asserting a particular attribute on the Mailable exists, for example subject the attribute shows up as null and the assertion fails:

Mail::assertSent(MyMailable::class, function ($mail) {
    return $mail->subject === 'My Subject';
});

I believe this is because I have configured all of the Mailable attributes within the build() method which at the stage of the assertion probably hasn't been invoked, so the attributes are not set on the object yet.

I thought using the build() method was the correct approach to take based on the docs:

All of a mailable class' configuration is done in the build method. Within this method, you may call various methods such as from, subject, view, and attach to configure the email's presentation and delivery.

https://laravel.com/docs/5.5/mail#writing-mailables

I have found that I can get assertions on the Mailable's attributes working when I instead set the attributes on the constructor:

class MyMail extends Mailable
{
    public function __construct()
    {
        $this->subject = 'My Subject';
    }

    public function build() {
        return $this->subject('My Subject')->view('emails/my-email')
    }
}

However, I feel this approach is wrong because I feel like I am changing my code to suit my tests.

So, I would like to know if there is a better approach to making assertions against attributes on a Mailable? Any help would be most appreciated, thank you!

EDIT 1

Test class (irrelevant code stripped out)

/** @test */
function a_notification_is_sent_when_an_application_is_updated()
{
    Mail::fake([RequiresVerification::class]);

    // some set up and factory methods called here...

    // the listener for this event sends mail
    ApplicationUpdated::dispatch($application);

    // this assertion passes
    Mail::assertSent(RequiresVerification::class);

    // this assertion does not pass when subject is set on the build()  
    // method but passes when subject is set on the constructor
    Mail::assertSent(RequiresVerification::class, function ($mail) use ($user) {
        return $mail->subject === 'hello';
    });
}

EDIT 2

I am currently looking at the hasRecipient() method, which all has* methods use, to see how it handles making assertions against what I assume are Mailable attributes (to, from, bcc, cc, etc). Perhaps the Mailable object can be extended to add new attribute assertions using a similar approach?

https://github.com/laravel/framework/blob/5.5/src/Illuminate/Mail/Mailable.php#L540


回答1:


You can make assertions against attributes configured in the build() method by calling the build() method within the assertSent closure before making the assertions:

Mail::assertSent(MyMailable::class, function ($mail) {
    $mail->build();
    return $mail->subject === 'My Subject';
});

Thanks to @ohffs on laracasts for helping with this: https://laracasts.com/discuss/channels/testing/how-to-make-assertions-on-a-laravel-mailable



来源:https://stackoverflow.com/questions/48298696/how-to-make-assertions-on-a-laravel-mailable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!