Thursday, January 30, 2014

Functional testing emails with mailcatcher, Zend_Mail and more

This is how I've got functional testing of email sending set up.

The idea is that in testing environment emails get caught on the server and phpunit can then query to check that the outgoing email looks correct.


1. Mailcatcher.


Mailcatcher is an SMTP server that receives email and provides a web, and more importantly REST API to see the emails sent.  So step 1 is to install it on the php application server VM.  It could, I suppose, have gone on a separate VM but that seemed overkill.

Install followed these instructions except that I needed some extra bits and bobs (on a Debian 7 box).  The error messages and some trial and error were enough to get this sorted.

sudo apt-get install ruby rubygems
sudo apt-get install ruby1.9.1-dev
sudo apt-get sqlite3 libsqlite3-dev
gem install mailcatcher
and the php.ini setting was actually

sendmail_path = "/usr/bin/env /var/lib/gems/1.9.1/gems/mailcatcher-0.5.12/bin/catchmail "
I don't think that in actual fact this is necessary in my case, because I'm using a Zend Framework SMTP transport, but setting this was helpful for testing while getting it all set up, and probably better safer to do just to avoid accidental spam mail.

Just running 'mailcatcher' works.  But that has it running on localhost (127.0.0.1) which isn't OK because I need to be able to access it from outside the VM.  mailcatcher is on the application server and my phpunit tests are running on the host box.  So starting like this:

$> mailcatcher --http-ip=0.0.0.0

did the job: it's now accessible from the host.  That one-liner is in a little bash script that can be called by the phing task on the host box that does all the VM initialisation prior to running tests (database reset, date/time reset, and now this).

So now I can see the mailcatcher interface at http://lamplight:1080 from the host box (where lamplight is mapping to that VM, of course).

2. Configuring the application.


We're using Zend_Mail (ZF 1, still) and the default transport is configured in the bootstrap.  The transport config options are in the core config file, so all I needed to do was set the host and port to 127.0.0.1 and 1025 respectively (I have a [functest] section of the config file).  It actually took me ages to get this working, but in the end it was irritatingly simple.

3. Querying mailcatcher from tests


I'm using a mailcatcher client without the behat stuff, which was as easy as adding "alexandresalome/mailcatcher": "*" to my composer.json file in the testing folder.  I can now use that client class in my phpunit tests to check that the emails sent are correct.

4. And next

I wonder if it'd be useful to have some assertions along the lines of this:

    $email = $this->retrieveLastEmailSent();
    $this->assertEmailRecipients(["bob@example.com", $email);
    $this->assertEmailSubject("Testing my lovely emails", $email);
    $this->assertEmailBody("Hi Bob, this is a test email", $email);

    $email2 = $this->retrieveEmailSent(1);  // gets the last but 1
    $this->assertEmailRecipients(["tracey@example.com", $email2);
    $this->assertEmailBody("Hi Tracey, this is a test email", $email2, "See how email-merges work!");
    $this->assertEmailAttachments("md5ofexpectedfileorsomething?", $email2);
    $this->assertEmailFrom("matt@example.com", $email2);



Along the lines of http://codeception.com/12-15-2013/testing-emails-in-php.html, most likely, although I think I'd like to have a try at creating my own assertion classes 'properly' (i.e. the way it's suggested in the phpunit manual in the section on extending it).

And a big thanks to the lovely people that have made these tools (Samuel Cochran and Alexandre Salomé).




1 comment:

  1. Hello,
    The Article on Functional testing emails with mailcatcher, Zend_Mail and more is informative.. It gives detailed information about it. Thanks for Sharing the information about the Functional testing For More information check the detail on Functional testing check,Software Testing Services


    ReplyDelete