How To Test Mail and Database Notifications in Laravel 8
Tags: tdd, php, laravel, notifications
Published: 2022-05-11 17:49:23

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](https://dev.to/macelux/test-driven-development-tdd-in-laravel-8-21kn) 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 :)