我正在使用通知,以便在触发通知时向所有用户发送邮件。
这在手动“浏览网站”用法(将POST提交给ContactController)中很好用,但是在我的测试中,邮件外观声称没有发送邮件。
控制器:
<?php
namespace App\Http\Controllers;
use App\Notifications\ContactRequestNotification;
use App\User;
use Illuminate\Http\Request;
use Notification;
class ContactController extends Controller
{
public function create(Request $request)
{
$validateData = $request->validate([
'name' => 'required',
'email' => 'required|email',
'message' => 'required'
]);
Notification::send(User::all(), new ContactRequestNotification($validateData));
return $validateData;
}
}
通知:
<?php
namespace App\Notifications;
use App\Mail\ContactMail;
use Illuminate\Mail\Mailable;
use Illuminate\Notifications\Notification;
class ContactRequestNotification extends Notification
{
/**
* @var array
*/
private $contactData;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($contactData)
{
$this->contactData = $contactData;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return Mailable
*/
public function toMail($notifiable)
{
return (new ContactMail($this->contactData['name'], $this->contactData['email'], $this->contactData['message']))->to($notifiable->email);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return $this->contactData;
}
}
可邮寄:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class ContactMail extends Mailable
{
use Queueable, SerializesModels;
/** @var string */
public $name;
/** @var string */
public $email;
/** @var string */
public $message;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($name, $email, $message)
{
$this->name = $name;
$this->email = $email;
$this->message = $message;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('emails.contact')
->from(env('MAIL_FROM'))
->subject('New contact request');
}
}
测试:
<?php
namespace Tests\Feature;
use App\Mail\ContactMail;
use App\Notifications\ContactRequestNotification;
use App\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Support\Facades\Mail;
use Notification;
use Tests\TestCase;
class ContactFormTest extends TestCase
{
use DatabaseMigrations;
/** @test */
public function a_notification_gets_created_when_the_contact_form_is_used()
{
Notification::fake();
$user = factory(User::class)->create();
$response = $this->post('/contact', [
'name' => 'John Doe',
'email' => 'email@email.com',
'message' => 'This is a test message'
]);
$response->assertStatus(200);
Notification::assertSentTo($user, ContactRequestNotification::class);
}
/** @test */
public function a_mail_is_send_when_the_contact_form_is_used()
{
$this->withExceptionHandling();
factory(User::class)->create();
Mail::fake();
Mail::assertNothingSent();
$data = [
'name' => 'John Doe',
'email' => 'email@email.com',
'message' => 'This is a test message'
];
$response = $this->post('/contact', $data);
$response->assertStatus(200);
Mail::assertSent(ContactMail::class, 1);
}
}
“ a_notification_gets_created_when_the_contact_form_is_used”测试运行没有问题,但是第二个测试用例导致:
/usr/bin/php /home/vendor/phpunit/phpunit/phpunit --configuration /home/phpunit.xml --filter "/(::a_mail_is_send_when_the_contact_form_is_used)( .*)?$/" Tests\Feature\ContactFormTest /home/tests/Feature/ContactFormTest.php --teamcity
PHPUnit 8.3.4 by Sebastian Bergmann and contributors.
The expected [App\Mail\ContactMail] mailable was sent 0 times instead of 1 times.
Failed asserting that false is true.
在浏览器中执行相同任务时,会将邮件发送给用户。
关于我在这里缺少什么的任何提示?互联网搜索显示其他一些人有此问题,但都没有找到解决方案(或者我无法执行正确的搜索)
谢谢!
答案 0 :(得分:1)
发送通知电子邮件的MailChannel
驱动程序似乎没有使用Mail
外观,这意味着Mail::fake
不会对其产生影响。相反,它直接在send
上调用Mailable
方法,然后在send
(邮件驱动程序)上调用Mailer
。
您可以将Mailable
实例替换为MailFake
的实例(Mail::fake
使用的实例),但是看起来MailFake
不能满足$view
是一个数组(MailChannel
传递给Mailable
的情况)。
幸运的是,Laravel源代码包含一个示例,说明了他们如何测试在SendingMailNotificationsTest
中发送邮件的通知。他们模拟Mailer
和Markdown
实例,并检查传递的参数。您可以执行类似的操作:
use Mockery as m;
use Illuminate\Contracts\Mail\Mailable;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Mail\Markdown;
use Illuminate\Mail\Message;
class ContactFormTest extends TestCase
{
protected function tearDown(): void
{
parent::tearDown();
m::close();
}
protected function setUp(): void
{
parent::setUp();
$this->mailer = m::mock(Mailer::class);
$this->markdown = m::mock(Markdown::class);
$this->instance(Mailer::class, $this->mailer);
$this->instance(Mailer::class, $this->markdown);
}
public function a_mail_is_send_when_the_contact_form_is_used()
{
$this->withExceptionHandling();
$user = factory(User::class)->create();
$this->markdown->shouldReceive('render')->once()->andReturn('htmlContent');
$this->markdown->shouldReceive('renderText')->once()->andReturn('textContent');
$data = [
'name' => 'John Doe',
'email' => 'email@email.com',
'message' => 'This is a test message'
];
$notification = new ContactRequestNotification($data);
$this->mailer->shouldReceive('send')->once()->with(
['html' => 'htmlContent', 'text' => 'textContent'],
array_merge($notification->toMail($user)->toArray(), [
'__laravel_notification' => get_class($notification),
'__laravel_notification_queued' => false,
]),
m::on(function ($closure) {
$message = m::mock(Message::class);
$message->shouldReceive('to')->once()->with([$user->email]);
$closure($message);
return true;
})
);
$response = $this->post('/contact', $data);
$response->assertStatus(200);
}
}
就我个人而言,我现在只想对toMail
类的ContactRequestNotification
方法进行单元测试,因为我认为上面的方法不是很漂亮。