The other team was refused. Sending a real email from a test is slow, and it fails when mail is not configured. Mail::fake() records the mailables instead of sending them. The test then asserts that the right one was queued, to the right address.
Test-driven Laravel · Lesson 3
Faking the mail
Video
01 Assert the mailable, not the inbox
InvoiceMail implements ShouldQueue, so the assertion is assertQueued. assertSent is for mail that goes out during the request.
it('queues the invoice email to the billing address', function () {
Mail::fake();
$invoice = Invoice::factory()->issued()->create();
$this->actingAs($invoice->team->owner)
->post('/invoices/'.$invoice->id.'/send')
->assertRedirect();
Mail::assertQueued(InvoiceMail::class, function (InvoiceMail $mail) use ($invoice) {
return $mail->hasTo($invoice->team->billing_email);
});
});Fake before the request. A fake installed afterwards does not see the mail the request already handed to the real mailer.
assertQueued does not prove the template renders. Render the mailable in one test if the view is the thing you are changing. Do not render it in every test that only cares the mail was queued.
02 Render the mailable when the view is the change
One test can build the mailable and assert the HTML. It does not send, and it does not need Mail::fake(), because nothing is handed to the mailer. assertSee() checks the invoice number the template was given.
it('renders the invoice number in the mail', function () {
$invoice = Invoice::factory()->issued()->create();
$html = (new InvoiceMail($invoice))->render();
expect($html)->toContain($invoice->number);
});Keep this test next to a view change. The queued test stays the one that proves the controller asked for the mail. A failure in render() is a broken template. A failure in assertQueued() is a controller that never dispatched it.
assertNothingQueued() belongs on the test where sending would be the bug, such as a validation failure. Mail::fake() still comes first. A test that forgets the fake and expects nothing can pass because the mailer is misconfigured, which is not the same as the controller staying quiet.
Recap
You can assert that an invoice mailable was queued to the billing address without sending it.
assertQueuedis forShouldQueuemail.assertSentis for mail that goes during the request.- Fake before the request.
- Render the mailable in the one test that is about the view.
Check yourself · 3 questions
Question 1 of 3InvoiceMail implements ShouldQueue. The test calls assertSent. What happens?