Summer Sale! All accounts are 50% off this week.

bcnmsg's avatar

Laravel 8 Notification Unit Testing not working: The expected notification was not sent

Hi community,

Context:

  • Laravel 8.83.18
  • PHPUnit 9.5.21
  • PHP 8.1.7

I'm trying to implement (it's my first time) a Unit Test for a use case that sends an email as a Laravel Notification. I am implementing my web app with a Domain-Driven Design approach and, to simplify and debug, I've checked Laravel Official Documentation (laravel com/docs/8.x/mocking#notification-fake), and I am trying to make the simplest case work, but it doesn't (without using my DDD approach that sends the notification through a use case). I will show you my code: Test Class:

<?php

declare(strict_types=1);

namespace Tests\Unit\Modules\Test;

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

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

        $emil = '[email protected]';
        $user = new User();
        $user->setAttribute('email', $emil);

        // Executing notification sending...
        Notification::route('mail',  $email)->notify(new TestNotification($user));

        // Assert a notification was sent to the given users...
        Notification::assertSentTo(
            [$user], TestNotification::class
        );
    }
}

Test Notification class:

<?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'
        ];
    }
}

Error Response:

The expected [App\Notifications\TestNotification] notification was not sent.
Failed asserting that false is true.
 /opt/project/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:83
 /opt/project/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:67
 /opt/project/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:261
 /opt/project/tests/Unit/Modules/Test/ExampleTest.php:27

Of course, if I try to send the notification out of the Unit Test, it works. I'm using this and I receive the email in my Mailhog container.

Route::get('/test-notification', function (){
    Notification::route('mail',  '[email protected]')->notify(new TestNotification(new \App\Models\User\User()));

    return 'Notification Sent';
});

So my question is, why the notification is not sent inside Unit Test, because my call it's the same, it does not match with Laravel says in their DOC.

In addition, I wonder if instead of using an instance of a Laravel model the user class, I can use another kind of object, even a Mock, I guess so, as long as I use the Trait "Notifiable". Correct?

Thank you very much

0 likes
0 replies

Please or to participate in this conversation.