zenstruck / mailer-test
用于测试通过symfony/mailer发送的电子邮件的替代、有观点的辅助工具。
v1.4.2
2024-08-15 01:29 UTC
Requires
- php: >=8.0
- symfony/framework-bundle: ^5.4|^6.0|^7.0
- symfony/mailer: ^5.4|^6.0|^7.0
- zenstruck/assert: ^1.0
- zenstruck/callback: ^1.1
Requires (Dev)
- phpstan/phpstan: ^1.4
- phpunit/phpunit: ^9.5.0
- symfony/messenger: ^5.4|^6.0|^7.0
- symfony/phpunit-bridge: ^6.0|^7.0
- symfony/var-dumper: ^5.4|^6.0|^7.0
- symfony/yaml: ^5.4|^6.0|^7.0
- zenstruck/browser: ^1.0
README
用于测试通过symfony/mailer
发送的电子邮件的替代、有观点的辅助工具。此包是FrameworkBundle的MailerAssertionsTrait
的替代品。
安装
- 安装库
composer require --dev zenstruck/mailer-test
- 如果symfony/flex没有自动添加,请在您的
test
环境中启用ZenstruckMailerTestBundle
用法
您可以通过在KernelTestCase/WebTestCase测试中使用InteractsWithMailer
特质与测试中的邮件发送器进行交互。
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Zenstruck\Mailer\Test\InteractsWithMailer; use Zenstruck\Mailer\Test\TestEmail; class MyTest extends KernelTestCase // or WebTestCase { use InteractsWithMailer; public function test_something(): void { // ...some code that sends emails... $this->mailer()->assertNoEmailSent(); $this->mailer()->assertSentEmailCount(5); $this->mailer()->assertEmailSentTo('kevin@example.com', 'the subject'); // For more advanced assertions, use a callback for the subject. // Note the \Zenstruck\Mailer\Test\TestEmail argument. This is a decorator // around \Symfony\Component\Mime\Email with some extra assertions. $this->mailer()->assertEmailSentTo('kevin@example.com', function(TestEmail $email) { $email ->assertSubject('Email Subject') ->assertSubjectContains('Subject') ->assertFrom('from@example.com') ->assertReplyTo('reply@example.com') ->assertCc('cc1@example.com') ->assertCc('cc2@example.com') ->assertBcc('bcc@example.com') ->assertTextContains('some text') ->assertHtmlContains('some text') ->assertContains('some text') // asserts text and html both contain a value ->assertHasFile('file.txt', 'text/plain', 'Hello there!') // tag/meta data assertions (https://symfony.ac.cn/doc/current/mailer.html#adding-tags-and-metadata-to-emails) ->assertHasTag('password-reset') ->assertHasMetadata('Color') ->assertHasMetadata('Color', 'blue') ; // Any \Symfony\Component\Mime\Email methods can be used $this->assertSame('value', $email->getHeaders()->get('X-SOME-HEADER')->getBodyAsString()); }); // reset collected emails $this->mailer()->reset(); } }
注意:在每次测试中,电子邮件在内核重启之间是持久化的。您可以使用$this->mailer()->reset()
重置收集到的电子邮件。
已发送电子邮件集合
您可以通过所有发送的电子邮件并筛选出您想要断言的电子邮件。大多数方法都是流畅的。
use Symfony\Component\Mime\Email; use Zenstruck\Mailer\Test\SentEmails; use Zenstruck\Mailer\Test\TestEmail; /** @var SentEmails $sentEmails */ $sentEmails = $this->mailer()->sentEmails(); $sentEmails->all(); // TestEmail[] $sentEmails->raw(); // Email[] $sentEmails->first(); // First TestEmail in collection or fail if none $sentEmails->last(); // Last TestEmail in collection or fail $sentEmails->count(); // # of emails in collection $sentEmails->dump(); // dump() the collection $sentEmails->dd(); // dd() the collection $sentEmails->each(function(TestEmail $email) { // do something with each email in collection }); $sentEmails->each(function(Email $email) { // can typehint as Email }); // iterate over collection foreach ($sentEmails as $email) { /** @var TestEmail $email */ } // assertions $sentEmails->assertNone(); $sentEmails->assertCount(5); // fails if collection is empty $sentEmails->ensureSome(); $sentEmails->ensureSome('custom failure message'); // filters - returns new instance of SentEmails $sentEmails->whereSubject('some subject'); // emails with subject "some subject" $sentEmails->whereSubjectContains('subject'); // emails where subject contains "subject" $sentEmails->whereFrom('sally@example.com'); // emails sent from "sally@example.com" $sentEmails->whereTo('sally@example.com'); // emails sent to "sally@example.com" $sentEmails->whereCc('sally@example.com'); // emails cc'd to "sally@example.com" $sentEmails->whereBcc('sally@example.com'); // emails bcc'd to "sally@example.com" $sentEmails->whereReplyTo('sally@example.com'); // emails with "sally@example.com" as a reply-to $sentEmails->whereTag('password-reset'); // emails with "password-reset" tag (https://symfony.ac.cn/doc/current/mailer.html#adding-tags-and-metadata-to-emails) // custom filter $sentEmails->where(function(TestEmail $email): bool { return 'password-reset' === $email->tag() && 'Some subject' === $email->getSubject(); }); // combine filters $sentEmails ->whereTag('password-reset') ->assertCount(2) ->each(function(TestEmail $email) { $email->assertSubjectContains('Password Reset'); }) ->whereTo('kevin@example.com') ->assertCount(1)
自定义TestEmail
上面显示的TestEmail
类是用于\Symfony\Component\Mime\Email
的一个装饰器,包含了一些断言。您可以通过扩展它来添加自己的断言。
namespace App\Tests; use PHPUnit\Framework\Assert; use Zenstruck\Mailer\Test\TestEmail; class AppTestEmail extends TestEmail { public function assertHasPostmarkTag(string $expected): self { Assert::assertTrue($this->getHeaders()->has('X-PM-Tag')); Assert::assertSame($expected, $this->getHeaders()->get('X-PM-Tag')->getBodyAsString()); return $this; } }
然后,在测试中使用它
use App\Tests\AppTestEmail; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Zenstruck\Mailer\Test\InteractsWithMailer; class MyTest extends KernelTestCase // or WebTestCase { use InteractsWithMailer; public function test_something(): void { // ...some code that sends emails... // Type-hinting the callback with your custom TestEmail triggers it to be // injected instead of the standard TestEmail. $this->mailer()->assertEmailSentTo('kevin@example.com', function(AppTestEmail $email) { $email->assertHasPostmarkTag('password-reset'); }); $this->mailer()->sentEmails()->each(function(AppTestEmail $email) { $email->assertHasPostmarkTag('password-reset'); }); // add your custom TestEmail as an argument to these methods to change the return type $this->mailer()->sentEmails()->first(AppTestEmail::class); // AppTestEmail $this->mailer()->sentEmails()->last(AppTestEmail::class); // AppTestEmail $this->mailer()->sentEmails()->all(AppTestEmail::class); // AppTestEmail[] } }
zenstruck/browser集成
此库提供了一个zenstruck/browser "组件" 和 "扩展"。由于浏览器向您的应用程序发送HTTP请求,消息通过分析器(使用symfony/mailer的数据收集器)访问。因此,在测试用例中不需要InteractsWithMailer
特质。由于需要分析器,此功能在PantherBrowser
中不可用。
MailerComponent
使用zenstruck/browser测试电子邮件的最简单方法是使用MailerComponent
use Zenstruck\Mailer\Test\Bridge\Zenstruck\Browser\MailerComponent; use Zenstruck\Mailer\Test\TestEmail; /** @var \Zenstruck\Browser\KernelBrowser $browser **/ $browser ->withProfiling() // enable the profiler for the next request ->visit('/page/that/does/not/send/email') ->use(function(MailerComponent $component) { $component->assertNoEmailSent(); }) ->withProfiling() // enable the profiler for the next request ->visit('/page/that/sends/email') ->use(function(MailerComponent $component) { $component ->assertSentEmailCount(1) ->assertEmailSentTo('kevin@example.com', 'Email Subject') ->assertEmailSentTo('kevin@example.com', function(TestEmail $email) { // see Usage section above for full API }) ; $component->sentEmails(); \Zenstruck\Mailer\Test\SentEmails }) ;
MailerExtension
如果您的许多测试都进行电子邮件断言,MailerComponent的API可能有点冗长。作为替代,您可以使用提供的MailerExtension
特质直接在一个自定义浏览器上添加方法
namespace App\Tests; use Zenstruck\Browser\KernelBrowser; use Zenstruck\Mailer\Test\Bridge\Zenstruck\Browser\MailerExtension; class AppBrowser extends KernelBrowser { use MailerExtension; }
现在,在您的测试中使用此自定义浏览器,以下电子邮件断言API可用
use Zenstruck\Mailer\Test\TestEmail; /** @var \App\Tests\AppBrowser $browser **/ $browser ->withProfiling() // enable the profiler for the next request ->visit('/page/that/does/not/send/email') ->assertNoEmailSent() ->withProfiling() // enable the profiler for the next request ->visit('/page/that/sends/email') ->assertSentEmailCount(1) ->assertEmailSentTo('kevin@example.com', 'Email Subject') ->assertEmailSentTo('kevin@example.com', function(TestEmail $email) { // see Usage section above for full API }) ;