问题
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