我正在 Symfony 6 項(xiàng)目的自定義類中使用 Symfony 郵件程序。我通過類的構(gòu)造函數(shù)中的類型提示使用自動(dòng)裝配,如下所示:
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, ]; } } }
在控制器中調(diào)用 sendEmail()
方法,一切正常。
現(xiàn)在我想測(cè)試 TransportException
s 是否被正確處理。為此,我需要郵件程序在我的測(cè)試中拋出 TransportException
s 。然而,這并沒有像我希望的那樣起作用。
注意:我無(wú)法通過傳遞無(wú)效的電子郵件地址來(lái)引發(fā)異常,因?yàn)?sendMail
方法只允許有效的電子郵件地址。
我嘗試過的事情:
1) 使用模擬郵件程序
// 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);
結(jié)果我無(wú)法模擬 Mailer
類,因?yàn)樗?final
。
2)使用模擬(或存根)MailerInterface
// create mock mailer service $mailer = $this->createStub(MailerInterface::class); $mailer->method('send') ->willThrowException(new TransportException()); $container->set('SymfonyComponentMailerMailer', $mailer);
沒有錯(cuò)誤,但不拋出異常。郵件服務(wù)似乎沒有被取代。
3) 使用自定義 MailerExceptionTester 類
// 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(); } }
在測(cè)試中:
// create mock mailer service $mailer = new MailerExceptionTester(); $container->set('SymfonyComponentMailerMailer', $mailer);
與 2) 中的結(jié)果相同
4)嘗試更換MailerInterface服務(wù)而不是Mailer
// create mock mailer service $mailer = $this->createMock(MailerInterface::class); $mailer->method('send') ->willThrowException(new TransportException()); $container->set('SymfonyComponentMailerMailerInterface', $mailer);
錯(cuò)誤消息:SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服務(wù)是私有的,您無(wú)法替換它。
5) 將 MailerInterface 設(shè)置為公開
// services.yaml services: SymfonyComponentMailerMailerInterface: public: true
錯(cuò)誤:無(wú)法實(shí)例化接口 SymfonyComponentMailerMailerInterface
6) 為 MailerInterface 添加別名
// services.yaml services: app.mailer: alias: SymfonyComponentMailerMailerInterface public: true
錯(cuò)誤消息:SymfonyComponentDependencyInjectionExceptionInvalidArgumentException:“SymfonyComponentMailerMailerInterface”服務(wù)是私有的,您無(wú)法替換它。
如何在測(cè)試中替換自動(dòng)連接的 MailerInterface
服務(wù)?
您第一次嘗試的順序應(yīng)該是正確的。
// boot kernel and get Class from container $container = self::getContainer(); $container->set('Symfony\Component\Mailer\Mailer', $mailer); // create mock mailer service $mailer = $this->createMock(Mailer::class); $mailer->method('send') ->willThrowException(new TransportException()); $myClass = $container->get('App\Model\MyClass');
未經(jīng)測(cè)試,但您將類作為對(duì)象獲取,因此在模擬之前已經(jīng)解決了對(duì)服務(wù)的依賴關(guān)系。這應(yīng)該首先替換容器中的服務(wù),然后從容器中獲取MyClass
。
但是,您也可以完全跳過容器的構(gòu)建。只需使用 PhpUnit。
$mock = $this->createMock(Mailer::class); // ... $myClass = new MyClass($mock); $myClass->sendEmail();
我正在嘗試這樣做,并且我相信我已經(jīng)根據(jù)您已經(jīng)嘗試過的方法找到了解決方案。
在我的 services.yaml
中,我重新聲明 mailer.mailer
服務(wù),并在測(cè)試環(huán)境中將其設(shè)置為公共:
when@test: services: mailer.mailer: class: Symfony\Component\Mailer\Mailer public: true arguments: - '@mailer.default_transport'
此設(shè)置應(yīng)該使 Symfony Mailer 服務(wù)的行為方式與以前完全相同,但是因?yàn)樗F(xiàn)在是公共的,所以如果需要,我們可以覆蓋它在容器中使用的類。
我復(fù)制了您編寫的自定義 Mailer 類...
// MailerExceptionTester.php...在我的測(cè)試代碼中,我獲取了測(cè)試容器并將
mailer.mailer
服務(wù)替換為異常拋出類的實(shí)例:$mailer = new MailerExceptionTester(); static::getContainer()->set('mailer.mailer', $mailer);現(xiàn)在,無(wú)論注入 Mailer 服務(wù),所使用的類都將是自定義異常拋出類!