How to Test Mail Notifications in Laravel ?

Vivek Dhumal
2 min readJun 17, 2018

--

I was testing some feature from my side project and I came across the situation where I want to test Mail Notification means I don’t want to send actual notification , I just wanted to fake it so that I can ensure that mail is getting send at some trigger point and also I wanted to test the content of that mail.

Well Laravel 5.6 already has something know as Notifications Fake out of the box, where you can actually mock the mail process and assert whether it is sent to the appropriate recipient or not, It is good, but How do I suppose to test whether my content from that mail is appropriate and it does have dynamic data?

Lets take the example test case from the documentation which sends notification to the user about order shipment.

<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

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

// Perform order shipping...

Notification::assertSentTo(
$user,
OrderShipped::class,
function ($notification, $channels) use ($order) {
return $notification->order->id === $order->id;
}
);
}
}

This is working fine, but how can we assert the mail content? well it is not mentioned in documentation but we can still do the thing, we can still write the various assertions to test the mail content. let see how in following example.

<?phpnamespace Tests\Feature;use Tests\TestCase;
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
public function testOrderShipping()
{
Notification::fake();
// Perform order shipping... Notification::assertSentTo(
$user,
OrderShipped::class,
function ($notification, $channels) use ($order, $user){
// retrive the mail content
$mailData = $notification->toMail($user)->toArray();
$this->assertEquals("Order #{$order->orderNumber} shipped", $mailData['subject']);
$this->assertEquals("Hello {$user->name}!", $mailData['greeting']);
$this->assertContains("Your order #{$order->orderNumber} has been shipped", $mailData['introLines']);
$this->assertEquals("View Order", $mailData['actionText']);
$this->assertEquals(route('orders.show', $order), $mailData['actionUrl']);
$this->assertContains("Thank You!", $mailData['outroLines']);
return $notification->order->id === $order->id;
}
);
}
}

Here you can see inside the closure we are retrieving the content of the mail using toMail() function which gives us the collection representation of the entire mail content and further we are converting it to the array which gives us different elements such as subject, greeting, intro lines, action text, action link, outro lines.

using the array we can write the basic phpunit text based assertions to ensure our mail content, which will gives you the full fledged solution about the mail testing.

This is great! this is the beauty of the Laravel Framework which gives you everything out of the box, only sometimes you have to dig dipper into their documentation.

Happy Coding ;)

--

--