How To Test Mail and Database Notifications in Laravel 8

Macdonald Chika
3 min readApr 24, 2022

--

I was working on a project in Laravel and needed to test the mail content of a mail notification and also the database notification but I could not figure it out. After some research, I figured that you can actually unit test or assert mail notification content as well as database notification without sending an actual notification. I will show you how to do that in this article.

If you are reading this, I will assume that you already know how to write unit tests in Laravel using PHPUnit. If you don't , you can click here to get you started.

Firstly, we will create a notification using this Laravel command

php artisan make:notification TestNotification

Your file should look like this.

<?php

namespace
App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class TestNotification extends Notification
{
use Queueable;

private $user;

public function __construct($user)
{
$this->$user = $user;
}

public function via($notifiable)
{
return ['mail','database'];
}

public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}

public function toArray($notifiable)
{
return [
'some' => 'data'
];
}
}

And then in your test, you should fake the notification by calling the notification facade and then a static function fake().

We are going to test the database notification. In your test file, create a function testDatabaseNotification(). Afterward, we will arrange our test case, act and assert.

public function testDatabaseNotification()
{
// Arrange
Notification::fake();
$this->user = User::factory()->create();
$email_subject = "Test Notification";

// Act
$this->user->notify(new TestNotification($email_subject));

// Assert
Notification::assertSentTo($this->user, TestNotification::class, function ($notification, $channels) use($email_subject){
$this->assertContains('database', $channels);

$databaseNotification = (object)$notification->toArray($this->user);
$this->assertEquals( $email_subject, $databaseNotification->title);

return true;
});
}

Now we are going to test our mail notification

public function testMailNotification()
{
// Arrange
Notification::fake();
$this->user = User::factory()->create();
$email_subject = "Test notification";

// Act
$this->user->notify(new TestNotification($email_subject));

// Assert
Notification::assertSentTo($this->user, TestNotification::class, function ($notification, $channels) use($email_subject){
$this->assertContains('mail', $channels);

$mailNotification = (object)$notification->toMail($this->user);
$this->assertEquals($email_subject, $mailNotification->subject,);

$this->assertEquals('The introduction to the notification.', $mailNotification->introLines[0]);
$this->assertEquals('Thank you for using our application!', $mailNotification->outroLines[0]);
$this->assertEquals('Notification Action', $mailNotification->actionText);
$this->assertEquals($mailNotification->actionUrl, url('/'));

return true;
});
}

You see here that we are retrieving the content of the mail notification.

Here is the full code

<?php

namespace
Tests\Unit;

use App\Notifications\TestNotification;
use Illuminate\Support\Facades\Notification;
use App\Model\User;
use Tests\TestCase;

class MailNotificationTest extends TestCase
{
/**
*
@var \Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|mixed
*/
private
$user;

/**
* A basic test example.
*
*
@return void
*/
public function
testDatabaseNotification()
{
Notification::fake();
$this->user = User::factory()->create();
$email_subject = "Test Notification";

$this->user->notify(new TestNotification($email_subject));

Notification::assertSentTo($this->user, TestNotification::class, function ($notification, $channels) use($email_subject){
$this->assertContains('database', $channels);

$databaseNotification = (object)$notification->toArray($this->user);
$this->assertEquals( $email_subject, $databaseNotification->title);

return true;
});
}

public function testMailNotification()
{
Notification::fake();
$this->user = User::factory()->create();
$email_subject = "Test notification";

$this->user->notify(new TestNotification($email_subject));

Notification::assertSentTo($this->user, TestNotification::class, function ($notification, $channels) use($email_subject){
$this->assertContains('mail', $channels);

$mailNotification = (object)$notification->toMail($this->user);
$this->assertEquals($email_subject, $mailNotification->subject,);

$this->assertEquals('The introduction to the notification.', $mailNotification->introLines[0]);
$this->assertEquals('Thank you for using our application!', $mailNotification->outroLines[0]);
$this->assertEquals('Notification Action', $mailNotification->actionText);
$this->assertEquals($mailNotification->actionUrl, url('/'));

return true;
});
}
}

Now we have successfully asserted mail and database content in Laravel notification.
Please share in the comment below what you think about this.

Happy Coding :)

--

--