Ich verwende den Symfony-Mailer in einer benutzerdefinierten Klasse in einem Symfony 6-Projekt. Ich verwende Autowiring über Typhinweise im Konstruktor der Klasse wie folgt:
class MyClass { public function __construct(private readonly MailerInterface $mailer) {} public function sendEmail(): array { // Email is sent down here try { $this->mailer->send($email); return [ 'success' => true, 'message' => 'Email sent', ]; } catch (TransportExceptionInterface $e) { return [ 'success' => false, 'message' => 'Error sending email: ' . $e, ]; } } }
Rufen Sie die sendEmail()
-Methode im Controller auf und alles funktioniert einwandfrei.
Jetzt möchte ich TransportException
s 是否被正确处理。为此,我需要邮件程序在我的测试中抛出 TransportException
s testen. Dies funktionierte jedoch nicht wie erhofft.
HINWEIS : Ich kann keine Ausnahme auslösen, indem ich eine ungültige E-Mail-Adresse übergebe, da die sendMail
-Methode nur gültige E-Mail-Adressen zulässt.
Dinge, die ich versucht habe:
1) Verwenden Sie ein simuliertes E-Mail-Programm
// boot kernel and get Class from container $container = self::getContainer(); $myClass = $container->get('AppModelMyClass'); // create mock mailer service $mailer = $this->createMock(Mailer::class); $mailer->method('send') ->willThrowException(new TransportException()); $container->set('SymfonyComponentMailerMailer', $mailer);
Es stellte sich heraus, dass ich nicht simulieren konnte Mailer
类,因为它是 final
.
2) Verwenden Sie Mock (oder Stub) MailerInterface
// create mock mailer service $mailer = $this->createStub(MailerInterface::class); $mailer->method('send') ->willThrowException(new TransportException()); $container->set('SymfonyComponentMailerMailer', $mailer);
Keine Fehler, aber keine Ausnahmen ausgelöst. Der Postdienst scheint nicht ersetzt worden zu sein.
3) Verwenden Sie die benutzerdefinierte MailerExceptionTester-Klasse
// MailerExceptionTester.php <?php namespace AppTests; use SymfonyComponentMailerEnvelope; use SymfonyComponentMailerExceptionTransportException; use SymfonyComponentMailerMailerInterface; use SymfonyComponentMimeRawMessage; /** * Always throws a TransportException */ final class MailerExceptionTester implements MailerInterface { public function send(RawMessage $message, Envelope $envelope = null): void { throw new TransportException(); } }
Im Test:
// create mock mailer service $mailer = new MailerExceptionTester(); $container->set('SymfonyComponentMailerMailer', $mailer);
Gleiches Ergebnis wie in 2)
4) Versuchen Sie, den MailerInterface-Dienst anstelle von Mailer
zu ändern// create mock mailer service $mailer = $this->createMock(MailerInterface::class); $mailer->method('send') ->willThrowException(new TransportException()); $container->set('SymfonyComponentMailerMailerInterface', $mailer);
Fehlermeldung: SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服务是私有的,您无法替换它。
5) MailerInterface auf öffentlich setzen
// services.yaml services: SymfonyComponentMailerMailerInterface: public: true
错误:无法实例化接口 SymfonyComponentMailerMailerInterface
6) Alias für MailerInterface hinzufügen
// services.yaml services: app.mailer: alias: SymfonyComponentMailerMailerInterface public: true
Fehlermeldung: SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服务是私有的,您无法替换它。
Wie ersetzt man einen automatisch verbundenen MailerInterface
Dienst in einem Test?
您第一次尝试的顺序应该是正确的。
未经测试,但您将类作为对象获取,因此在模拟之前已经解决了对服务的依赖关系。这应该首先替换容器中的服务,然后从容器中获取
MyClass
。但是,您也可以完全跳过容器的构建。只需使用 PhpUnit。
我正在尝试这样做,并且我相信我已经根据您已经尝试过的方法找到了解决方案。
在我的
services.yaml
中,我重新声明mailer.mailer
服务,并在测试环境中将其设置为公共:此设置应该使 Symfony Mailer 服务的行为方式与以前完全相同,但是因为它现在是公共的,所以如果需要,我们可以覆盖它在容器中使用的类。
我复制了您编写的自定义 Mailer 类...