I'm wondering, if there is an easy and direct way to test the email's subject using the new Mailable function of Laravel
I have a class which can send 5 different emails, but all of them to the same person, so that testing if an email was sent to a concrete person is not really a complete test. I need to know if a concrete email was sent to a concrete person.
I think, using the email's subject to test the uniqueness is the best way. If you have a better way please tell me.
I have this:
Mail::assertSentTo([Config::get('mail.backend')], SendEmail::class);
And I would like to add something like this
Mail::assertSubject('My Subject', SendEmail::class);
Is there a way to do this??
Thank you!
Quick and better solution than mine found at How to make assertions on a Laravel Mailable, thanks to @haakym
Just call the build()
method before asserting:
Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
$mail->build();
return $mail->subject = 'The SUBJECT that I very much need';
});
Any way I still prefer
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;
});
I see this question has been here for a while, but I stumbled into the same thing.
(Important: of all this is for testing one single mail).
In the docs about mocking a Mail you can see:
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('...');
});
}
}
This would ease any solution, right? You should be able to do something like:
Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
return $mail->subject = 'The SUBJECT that I very much need';
});
and that should work. Right? Well, it wont unless you do things a little different.
In the Mail guide, every example they present uses the build
method:
public function build()
{
return $this->from('[email protected]')
->subject('The SUBJECT that I very much need')
->view('emails.orders.shipped');
}
The thing is that when you call Mail::fake()
at the top of your method you turn the whole Mail system into a Illuminate\Support\Testing\Fakes\MailFake (that's why it supports the assertSent
method amongst others), and this implies that the custom build
function never gets called.
You should start using more the __constructor
method on the Mailable class. And just return the instance in the build()
method:
Following (and modifying) the view example in the Mail guide:
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;
}
}
This being said, now this works:
Mail::fake();
...
Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
return $mail->subject == 'The SUBJECT that I very much need';
});
I'll rather do something like this, because I feel the control is much more grained:
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;
});
}
}
The way assert
works in unit testing will never walk by a wrong condition. :)
With 5.4
To perform the test you have in your question you would do:
Mail::assertSent(SendEmail::class, function ($mail) {
return $mail->hasTo(Config::get('mail.backend'));
});
to test that the subject you could do something like:
Mail::assertSent(SendEmail::class, function ($mail) {
return $mail->hasTo(Config::get('mail.backend'))
&& $mail->subject == 'My Subject';
});
https://laravel.com/docs/5.4/mocking#mail-fake
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With