[英]Laravel unit testing emails
我的系統發送了幾封重要的電子郵件。 單元測試的最佳方法是什么?
我看到您可以將其置於假裝模式並記錄在日志中。 有什么可以檢查的嗎?
有兩種選擇。
選項 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('foo@bar.com', $msg->getTo());
$this->assertContains('Some string', $msg->getBody());
});
選項 2 更容易 - 它是使用MailCatcher.me測試實際的 SMTP。 基本上,您可以發送 SMTP 電子郵件,並“測試”實際發送的電子郵件。 Laracasts 有一個關於如何在 Laravel 測試中使用它的重要課程。
對於 Laravel 5.4 檢查Mail::fake()
: https ://laravel.com/docs/5.4/mocking#mail-fake
“@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(['foo@bar.com' => null], $message->getTo());
$this->assertContains('Some string', $message->getBody());
return true;
}), \Mockery::any()])
->once();
如果您只是不想真正發送電子郵件,則可以使用“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
}
}
如果有人使用 docker 作為開發環境,我最終會通過以下方式解決這個問題:
.env
...
MAIL_FROM = noreply@example.com
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
# update ...
'port' => env('MAIL_PORT', 587),
# to ...
'port' => env('EMAIL_PORT', 587),
(由於某種原因,我與這個環境變量發生了沖突)
進行...
docker-compose.ymal
mail:
image: schickling/mailcatcher
ports:
- 1080:1080
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('someone@example.com')->send(new SomeMail('Body of the email'));
...
}
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
<h1>{{ $body }}</h1>
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('someone@example.com', array_keys($emails[0]->getTo())[0]);
}
...
private function deleteAllEmailMessages()
{
$mailcatcher = new Client(['base_uri' => config('mailtester.url')]);
$mailcatcher->delete('/messages');
}
}
(這是從我自己的代碼中復制和編輯的,所以第一次可能不起作用)
我認為檢查日志不是好方法。
您可能想看看如何模擬 Mail 外觀並檢查它是否收到帶有一些參數的調用。
如果你在 laravel 中使用通知,你可以像下面那樣做
Notification::fake();
$this->post(...);
$user = User::first();
Notification::assertSentTo([$user], VerifyEmail::class);
如果您想測試電子郵件周圍的所有內容,請使用
Mail::fake()
但是如果你想測試你的Illuminate\\Mail\\Mailable
和blade
,那么按照這個例子。 假設,您想測試有關某些付款的提醒電子郵件,其中電子郵件文本應包含名為“valorant”的產品和一些以“美元”表示的價格。
public function test_PaymentReminder(): void
{
/* @var $payment SalePayment */
$payment = factory(SalePayment::class)->create();
auth()->logout();
$paymentReminder = new PaymentReminder($payment);
$html = $paymentReminder->render();
$this->assertTrue(strpos($html, 'valorant') !== false);
$this->assertTrue(strpos($html, 'USD') !== false);
}
這里的重要部分是->render()
- 這就是你如何讓Illuminate\\Mail\\Mailable
運行build()
函數並處理blade
。
另一個重要的事情是auth()->logout();
- 因為通常在后台環境中運行的隊列中處理電子郵件。 這個環境沒有用戶,沒有沒有URL和IP的請求......
因此,您必須確保在與生產環境類似的環境中,在單元測試中呈現電子郵件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.