Laravel 单元测试邮件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25222570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel unit testing emails
提问by T3chn0crat
My system sends a couple of important emails. What is the best way to unit test that?
我的系统发送了几封重要的电子邮件。单元测试的最佳方法是什么?
I see you can put it in pretend mode and it goes in the log. Is there something to check that?
我知道您可以将其置于假装模式并记录在日志中。有什么可以检查的吗?
回答by Laurence
There are two options.
有两种选择。
Option 1 - Mock the mail facade to test the mail is being sent. Something like this would work:
选项 1 - 模拟邮件外观以测试正在发送的邮件。像这样的事情会起作用:
$mock = Mockery::mock('Swift_Mailer');
$this->app['mailer']->setSwiftMailer($mock);
$mock->shouldReceive('send')->once()
->andReturnUsing(function($msg) {
$this->assertEquals('My subject', $msg->getSubject());
$this->assertEquals('[email protected]', $msg->getTo());
$this->assertContains('Some string', $msg->getBody());
});
Option 2 is much easier - it is to test the actual SMTP using MailCatcher.me. Basically you can send SMTP emails, and 'test' the email that is actuallysent. Laracasts has a great lesson on how to use it as part of your Laravel testing here.
选项 2 更容易 - 它是使用MailCatcher.me测试实际的 SMTP 。基本上,您可以发送 SMTP 电子邮件,并“测试”实际发送的电子邮件。Laracasts 有一个关于如何在 Laravel 测试中使用它的重要课程。
回答by Slava V
For Laravel 5.4 check Mail::fake()
:
https://laravel.com/docs/5.4/mocking#mail-fake
对于 Laravel 5.4 检查Mail::fake()
:https:
//laravel.com/docs/5.4/mocking#mail-fake
回答by happy_marmoset
"Option 1" from "@The Shift Exchange" is not working in Laravel 5.1, so here is modified version using Proxied Partial Mock:
“@The Shift Exchange”中的“Option 1”在 Laravel 5.1 中不起作用,所以这里是使用 Proxied Partial Mock 的修改版本:
$mock = \Mockery::mock($this->app['mailer']->getSwiftMailer());
$this->app['mailer']->setSwiftMailer($mock);
$mock
->shouldReceive('send')
->withArgs([\Mockery::on(function($message)
{
$this->assertEquals('My subject', $message->getSubject());
$this->assertSame(['[email protected]' => null], $message->getTo());
$this->assertContains('Some string', $message->getBody());
return true;
}), \Mockery::any()])
->once();
回答by Thiago Mata
If you just don't want the e-mails be really send, you can turn off them using the "Mail::pretend(true)"
如果您只是不想真正发送电子邮件,则可以使用“Mail::pretend(true)”关闭它们
class TestCase extends Illuminate\Foundation\Testing\TestCase {
private function prepareForTests() {
// e-mail will look like will be send but it is just pretending
Mail::pretend(true);
// if you want to test the routes
Route::enableFilters();
}
}
class MyTest extends TestCase {
public function testEmail() {
// be happy
}
}
回答by Sevenearths
If any one is using docker as there development environment I end up solving this by:
如果有人使用 docker 作为开发环境,我最终会通过以下方式解决这个问题:
Setup
设置
.env
.env
...
MAIL_FROM = [email protected]
MAIL_DRIVER = smtp
MAIL_HOST = mail
EMAIL_PORT = 1025
MAIL_URL_PORT = 1080
MAIL_USERNAME = null
MAIL_PASSWORD = null
MAIL_ENCRYPTION = null
config/mail.php
config/mail.php
# update ...
'port' => env('MAIL_PORT', 587),
# to ...
'port' => env('EMAIL_PORT', 587),
(I had a conflict with this environment variable for some reason)
(由于某种原因,我与这个环境变量发生了冲突)
Carrying on...
进行...
docker-compose.ymal
docker-compose.ymal
mail:
image: schickling/mailcatcher
ports:
- 1080:1080
app/Http/Controllers/SomeController.php
app/Http/Controllers/SomeController.php
use App\Mail\SomeMail;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
class SomeController extends BaseController
{
...
public function getSomething(Request $request)
{
...
Mail::to('[email protected]')->send(new SomeMail('Body of the email'));
...
}
app/Mail/SomeMail.php
app/Mail/SomeMail.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SomeMail extends Mailable
{
use Queueable, SerializesModels;
public $body;
public function __construct($body = 'Default message')
{
$this->body = $body;
}
public function build()
{
return $this
->from(ENV('MAIL_FROM'))
->subject('Some Subject')
->view('mail.someMail');
}
}
resources/views/mail/SomeMail.blade.php
resources/views/mail/SomeMail.blade.php
<h1>{{ $body }}</h1>
Testing
测试
tests\Feature\EmailTest.php
tests\Feature\EmailTest.php
use Tests\TestCase;
use Illuminate\Http\Request;
use App\Http\Controllers\SomeController;
class EmailTest extends TestCase
{
privete $someController;
private $requestMock;
public function setUp()
{
$this->someController = new SomeController();
$this->requestMock = \Mockery::mock(Request::class);
}
public function testEmailGetsSentSuccess()
{
$this->deleteAllEmailMessages();
$emails = app()->make('swift.transport')->driver()->messages();
$this->assertEmpty($emails);
$response = $this->someController->getSomething($this->requestMock);
$emails = app()->make('swift.transport')->driver()->messages();
$this->assertNotEmpty($emails);
$this->assertContains('Some Subject', $emails[0]->getSubject());
$this->assertEquals('[email protected]', array_keys($emails[0]->getTo())[0]);
}
...
private function deleteAllEmailMessages()
{
$mailcatcher = new Client(['base_uri' => config('mailtester.url')]);
$mailcatcher->delete('/messages');
}
}
(This has been copied and edited from my own code so might not work first time)
(这是从我自己的代码中复制和编辑的,所以第一次可能不起作用)
回答by Antoine Augusti
I think that inspecting the log is not the good way to go.
我认为检查日志不是好方法。
You may want to take a look at how you can mock the Mail facade and check that it receives a call with some parameters.
您可能想看看如何模拟 Mail 外观并检查它是否收到带有一些参数的调用。