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.
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 :)
Top comments (0)