先に結論
次のようにしてできる。
use Illuminate\Notifications\AnonymousNotifiable;
Notification::fake();
// :
// テスト対象のロジック実行
// :
Notification::assertSentTo(
new AnonymousNotifiable(),
InvoicePaid::class, // 対象の Notification class
function($notification, $channels, $notifiable) {
return $notifiable->routes['mail'] == 'test@example.com';
}
);
前提1:On-Demand Notifications とは?
メール送信のような「通知」を行う際には通常、 Illuminate\Notifications\Notifiable
trait を use
した class に対して notify()
メソッドを実行する。
On-Demand Notifications はそのような class が存在しない対象に対して、直接通知を行うための仕組みである。
Notification::route('mail', 'taylor@example.com')
->route('nexmo', '5555555555')
->notify(new InvoicePaid($invoice));
例えば私は、「フォームにメールアドレスだけ入力してもらって、アカウント登録フォームの URL をそのメールアドレスに送信する」という場面で使っている。1
前提2:Notifications をモック化してテスト
テストを実行では、実際にメール送信等はしたくない。
そこで、Laravel では Notifications をモック化する仕組みを提供している。
Notification::fake();
// Perform order shipping...
Notification::assertSentTo(
$user,
OrderShipped::class,
function ($notification, $channels) use ($order) {
return $notification->order->id === $order->id;
}
);
このモック化のおかげで、実際にメールを送信することなく「対象にメールが送信されること」を確かめるテストを書くことができる。
本題:On-Demand Notifications をモック化してテスト
しかし、公式ドキュメントの情報からだけでは On-Demand Notifications を使っている場合にモック化する方法がわからない。
Notification::fake();
// こんな風にしていい感じに解釈してくれないかな、と期待したが
Notification::assertSentTo(
'test@exmaple.com',
InvoicePaid::class
);
# こんなエラーで怒られる
ErrorException: get_class() expects parameter 1 to be object, string given
/var/www/app/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:165
/var/www/app/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:153
/var/www/app/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:129
/var/www/app/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:43
/var/www/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:221
:(以下略)
実は解決方法は Laravel5.5 の時点で既に提示されており、
use Illuminate\Notifications\AnonymousNotifiable;
Notification::fake();
// :
// テスト対象のロジック実行
// :
Notification::assertSentTo(
new AnonymousNotifiable(),
InvoicePaid::class, // 対象の Notification class
function($notification, $channels, $notifiable) {
return $notifiable->routes['mail'] == 'test@example.com';
}
);
のようにすることで、めでたくモック化してテストできる。
余談:AnonymousNotifiable
とは?
On-Demand Notifications を利用するときに出てくる Notifialbe な class こそが AnonymousNotifiable
。
>>> \Notification::route('mail', 'test@example.com')
=> Illuminate\Notifications\AnonymousNotifiable {
+routes: [
"mail" => "test@example.com",
],
}
-
ちなみに、Laravel 5.7 よりその機能自体が提供されたよう(https://laravel.com/docs/5.7/releases#laravel-5.7) ↩