我正在 Symfony 6 專(zhuān)案的自訂類(lèi)別中使用 Symfony 郵件程式。我透過(guò)類(lèi)別的建構(gòu)函式中的型別提示使用自動(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, ]; } } }
在控制器中呼叫 sendEmail()
方法,一切正常。
現(xiàn)在我想測(cè)試 TransportException
s 是否被正確處理。為此,我需要郵件程式在我的測(cè)試中拋出 TransportException
s 。然而,這並沒(méi)有像我希望的那樣運(yùn)作。
注意:我無(wú)法透過(guò)傳遞無(wú)效的電子郵件地址來(lái)引發(fā)異常,因?yàn)?sendMail
方法只允許有效的電子郵件地址。
我嘗試過(guò)的事情:
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
類(lèi),因?yàn)樗?final
。
2)使用模擬(或存根)MailerInterface
#// create mock mailer service $mailer = $this->createStub(MailerInterface::class); $mailer->method('send') ->willThrowException(new TransportException()); $container->set('SymfonyComponentMailerMailer', $mailer);
沒(méi)有錯(cuò)誤,但不拋出例外。郵件服務(wù)似乎沒(méi)有被取代。
3) 使用自訂 MailerExceptionTester 類(lèi)別
// 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è)定為公開(kāi)
#// 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è)試,但您將類(lèi)別作為物件獲取,因此在模擬之前已經(jīng)解決了對(duì)服務(wù)的依賴(lài)關(guān)係。這應(yīng)該先替換容器中的服務(wù),然後從容器中取得MyClass
。
但是,您也可以完全跳過(guò)容器的建置。只需使用 PhpUnit。
$mock = $this->createMock(Mailer::class); // ... $myClass = new MyClass($mock); $myClass->sendEmail();
我正在嘗試這樣做,我相信我已經(jīng)根據(jù)您已經(jīng)嘗試過(guò)的方法找到了解決方案。
在我的 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)該會(huì)使 Symfony Mailer 服務(wù)的行為方式與以前完全相同,但因?yàn)樗F(xiàn)在是公共的,所以如果需要,我們可以覆蓋它在容器中使用的類(lèi)別。
我複製了您編寫(xiě)的自訂 Mailer 類(lèi)別...
// MailerExceptionTester.php...在我的測(cè)試程式碼中,我取得了測(cè)試容器並將
mailer.mailer
服務(wù)替換為異常拋出類(lèi)別的實(shí)例:$mailer = new MailerExceptionTester(); static::getContainer()->set('mailer.mailer', $mailer);現(xiàn)在,無(wú)論注入 Mailer 服務(wù),所使用的類(lèi)別都會(huì)是自訂例外狀況拋出類(lèi)別!