Laravel 单元测试电子邮件

问题描述 投票:0回答:9

我的系统发送了几封重要的电子邮件。 单元测试的最佳方法是什么?

我看到你可以将其置于假装模式,它会记录在日志中。有什么可以检查的吗?

php laravel laravel-4
9个回答
14
投票

有两种选择。

选项 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());
    });

选项 2 更容易 - 它是使用 MailCatcher.me 测试实际的 SMTP。基本上,您可以发送 SMTP 电子邮件,并“测试”“实际”发送的电子邮件。 Laracasts 在此处提供了有关如何使用它作为 Laravel 测试一部分的精彩课程


6
投票

$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();



6
投票
Mail::fake()

https://laravel.com/docs/5.4/mocking#mail-fake


3
投票

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 } }



2
投票

设置

.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


# 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('[email protected]')->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('[email protected]', array_keys($emails[0]->getTo())[0]); } ... private function deleteAllEmailMessages() { $mailcatcher = new Client(['base_uri' => config('mailtester.url')]); $mailcatcher->delete('/messages'); } }

(这是从我自己的代码复制和编辑的,所以第一次可能不起作用)

(来源:

https://stackoverflow.com/a/52177526/563247


1
投票

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...

因此,您必须确保在单元测试中在与生产环境类似的环境中渲染电子邮件。


0
投票

您可能想看看如何模拟 Mail 外观并检查它是否收到带有某些参数的调用。


0
投票
Notifcations

,你可以像下面这样做 Notification::fake(); $this->post(...); $user = User::first(); Notification::assertSentTo([$user], VerifyEmail::class);

https://laravel.com/docs/7.x/mocking#notification-fake


0
投票

我的建议是使用像

Msgdrop

这样的 API,您可以在测试中使用 RESTful API 创建临时/一次性(真实)电子邮件地址,然后在测试中使用该地址。 示例:

curl https://api.msgdrop.io/v1/addresses \ -H 'Authorization: Bearer {YOUR_API_KEY}' \ --data ''

然后您可以通过另一个 RESTful API 调用从收件箱检索电子邮件:

curl https://api.msgdrop.io/v1/inbox/{CREATED_EMAIL_ADDRESS_ID}\ -H 'Authorization: Bearer {YOUR_API_KEY}'

响应将是一个大的 JSON 对象,其中包含有关电子邮件的所有信息,包括收件人、抄送、密件抄送、主题、HTML 和纯文本内容、附件、链接甚至垃圾邮件分数。

像这样的 API 驱动测试方法也比使用一些 UI 驱动测试更可靠,其中 UI 元素不断变化并破坏测试,而且恕我直言,它也比所有那些假 SMTP 服务器更好,因为您的软件可以使用信誉良好的电子邮件发送服务,例如 Mailgun 或SendGrid 并仍然以相同的方式测试电子邮件。您将无法将 SendGrid 的 SMTP 设置配置到假服务器。

查看非常广泛的文档:

https://docs.msgdrop.io

© www.soinside.com 2019 - 2024. All rights reserved.