Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test email sending with no controller

My application sends many emails. The official doc tells how to test emails sending with the HTTP client profiler.

But I obviously don't have a Controller for each email I'm sending.

How can I test my emails that are not triggered from a controller ? (I mean not from a request context).


Further detail on my specific case

I'm using a listener to trigger calls to a service which is doing the "email routing"
What I'd like to do here, is fire some events and check what is sent (the email body, title, recipients, ...)

like image 756
Pierre de LESPINAY Avatar asked Dec 10 '25 19:12

Pierre de LESPINAY


2 Answers

Following this great post I extended the Swift_MemorySpool

class CountableMemorySpool extends \Swift_MemorySpool implements \Countable
{
    public function count()
    {
        return count($this->messages);
    }

    public function getMessages()
    {
        return $this->messages;
    }
}

Passed it to the mailer used by my service

class MailServiceTest extends KernelTestCase
{
    protected $mailService;
    protected $spool;
// ...
    protected function setUp()
    {
        $this->spool = new CountableMemorySpool();
        $transport = new \Swift_Transport_SpoolTransport(
            new \Swift_Events_SimpleEventDispatcher(),
            $this->spool
        );
        $mailer = new \Swift_Mailer($transport);
        $this->mailService->setMailer($mailer);
    }

And tested

    // ...
    public function testMailSpec()
    {
        // ... Sending the mail ...
        $this->assertCount(1, $this->spool,
            'Expected exactly one email to be sent');
        $msg = $this->spool->getMessages()[0];
        $this->assertArrayHasKey('[email protected]', $msg->getTo(),
            'Wrong recipient');
        $this->assertContains('Tartempion', $msg->getBody(),
            'Expected some string contained in the email body');
    }
}
like image 163
Pierre de LESPINAY Avatar answered Dec 13 '25 11:12

Pierre de LESPINAY


First of all, the article you're linking at is about functional (e2e) testing, not the unit.

Second, for unit-testing you need to inject some MailerMocker in your Listener (which sends emails) instead of real Mailer.

For example, you may create a simple Mocker like this

class SwiftMailerTester extends \Swift_Mailer
{

    /**
     * @var array[\Swift_Mime_Message]
     *
     */

    protected $sentMessages = array ();

    /**
     * @var \Swift_Mime_Message
     */

    protected $lastSentMessage;

    public function __construct() {

    }
    /**
     * Mocks sending message
     *
     * @param \Swift_Mime_Message $message
     * @param null                $failedRecepients
     *
     * @return int
     */
    public function send(\Swift_Mime_Message $message, &$failedRecepients = null)
    {

        $this->lastSentMessage = $message;
        $this->sentMessages[] = $message;

        return 1;
    }

    /**
     * @return array[\Swift_Mime_Message]
     */
    public function getSentMessages()
    {
        return $this->sentMessages;
    }

    /**
     * @return \Swift_Mime_Message
     */

    public function getLastSentMessage()
    {
        return $this->lastSentMessage;
    }

    /**
     * @return int
     */
    public function getSentMessagesCount()
    {
        return count($this->sentMessages);
    }
}

And then in your unit test access lastSentMessage (or sentMessages) to analyze if Listener had done it's work right.

like image 28
Dmitry Malyshenko Avatar answered Dec 13 '25 11:12

Dmitry Malyshenko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!