Page 1 of 1

how did you test swiftmailer?

Posted: Wed Mar 21, 2007 7:02 pm
by Luke
Chris, how did you test swiftmailer? Is there some sort of fake server or something you tested it with? Say I want to write some code to send to 1000s of people... but I don't currently have 1000s of emails to test that it works. How do I test it? :?

(yes that is two questions. :) )

Posted: Thu Mar 22, 2007 12:40 am
by feyd
Lastcraft's fake email server?

Posted: Thu Mar 22, 2007 2:35 am
by Chris Corbyn
Nope, things like this in the testcases.... Mocks dude, Mocks :)

Code: Select all

protected function getWorkingMockConnection($send=1, $conn=null, $reconnect_at=0, $max_reconnect=0)
        {
                $count = 0;
                if (!$conn) $conn = new FullMockConnection();
                $conn->setReturnValueAt($count++, "read", "220 xxx ESMTP");
                $conn->setReturnValueAt($count++, "read", "250-Hello xxx\r\n250 HELP");
                $cycle = 0;
                $reconnected = 0;
                for ($i = 0; $i < $send; $i++)
                {
                        $cycle++;
                        $conn->setReturnValueAt($count++, "read", "250 Ok");
                        $conn->setReturnValueAt($count++, "read", "250 Ok");
                        $conn->setReturnValueAt($count++, "read", "354 Go ahead");
                        $conn->setReturnValueAt($count++, "read", "250 Ok");
                        if ($reconnect_at && $reconnect_at == $cycle)
                        {
                                if (!$max_reconnect || $max_reconnect > $reconnected)
                                {
                                        $conn->setReturnValueAt($count++, "read", "221 Bye");
                                        $conn->setReturnValueAt($count++, "read", "220 xxx ESMTP");
                                        $conn->setReturnValueAt($count++, "read", "250-Hello xxx\r\n250 HELP");
                                        $cycle = 0;
                                        $reconnected++;
                                }
                        }
                }
                $conn->setReturnValue("read", "250 Ok");
                return $conn;
        }
I need to refactor my tests actually because I started to copy that method into other testcases which I needn't have done.

The Units can't test everything, for example, they can't test if the email looks right. The smoke tests are the icing on the cake and act as end-to-end tests. At this point I always run the units and if they all pass I can assume the next step will but I go on to run all 5 smoke tests. I'm lucky in the respect of Swift's user-base size because if I release something with a problem in it, it will get picked up pretty fast. People seem pretty good at taking the initiative to email if something doesn't work properly.

EDIT | If you mean you want to quite literally test sending to 1000 addresses, just loop 1000 times with the same address. You can use that method above as a mock connection though (just mock Swift_Connection to create FullMockConnection).

Code: Select all

$mock_conn = $this->getWorkingMockConnection(1000);
That's ready to send 1000 emails, but not actually send them.

Posted: Mon Apr 02, 2007 5:02 pm
by Luke
getting this error when I do that:
error wrote:Fatal error: Call to a member function tell() on a non-object in C:\htdocs\library\simpletest\mock_objects.php on line 445

Posted: Mon Apr 02, 2007 5:19 pm
by Chris Corbyn
That's some weird simpletest error. Works ok for me (slightly refactored):

Code: Select all

<?php

/**
 * SwiftMailer Unit Testing Component.
 * Provides a testcase with functionality to get a Working Mock Connection.
 * @package Swift
 * @subpackage Tests
 * @author Chris Corbyn <chris@w3style.co.uk>
 */

Mock::Generate("Swift_Connection", "FullMockConnection");

/**
 * SwiftMailer Abstract test with sending capabilities.
 * Provides a testcase with functionality to get a Working Mock Connection.
 * @package Swift
 * @subpackage Tests
 * @author Chris Corbyn <chris@w3style.co.uk>
 */
abstract class AbstractTestWithSend extends UnitTestCase
{
	/**
	 * Get a mock connection for testing.
	 * The mock will be set up to send to X addresses (sccuessfully).
	 * The mock can also be configured to reconnect after X emails have been sent.
	 * @param int The number emails you expect to send
	 * @param Swift_Connection A mocked object which has not been setup yet, optional
	 * @param int The number of emails to send before reconnecting, optional
	 * @param int The maximum number of times the connection will re-connect, optional
	 * @param boolean True if the same email is copied to all recipients
	 * @return FullMockConnection
	 */
	protected function getWorkingMockConnection($send=1, $conn=null, $reconnect_at=0, $max_reconnect=0, $duplicate=false)
	{
		$count = 0;
		if (!$conn) $conn = new FullMockConnection();
		$conn->setReturnValueAt($count++, "read", "220 xxx ESMTP");
		$conn->setReturnValueAt($count++, "read", "250-Hello xxx\r\n250-AUTH PLAIN\r\n250 HELP");
		$cycle = 0;
		$reconnected = 0;
		for ($i = 0; $i < $send; $i++)
		{
			$conn->setReturnValueAt($count++, "read", "250 Ok");
			if (!$duplicate || ($i == $send-1))
			{
				$cycle++;
				$conn->setReturnValueAt($count++, "read", "250 Ok");
				$conn->setReturnValueAt($count++, "read", "354 Go ahead");
				$conn->setReturnValueAt($count++, "read", "250 Ok");
			}
			if ($reconnect_at && $reconnect_at == $cycle)
			{
				if (!$max_reconnect || $max_reconnect > $reconnected)
				{
					$conn->setReturnValueAt($count++, "read", "220 xxx ESMTP");
					$conn->setReturnValueAt($count++, "read", "250-Hello xxx\r\n250 HELP");
					$cycle = 0;
					$reconnected++;
				}
			}
		}
		$conn->setReturnValue("read", "250 ok");
		$conn->setReturnValue("isAlive", true);
		return $conn;
	}
}

Code: Select all

<?php

class TestOfFoo extends AbstractTestWithSend
{
    public function testFoo()
    {
        $mock_conn = $this->getWorkingMockConnection(1);
        $swift = new Swift($mock_conn);
        $this->assertEqual(1, $swift->send(new Swift_Message("xx", "yy"), "test@test.tld", "test@test.tld"));
    }
}
The mock here acts purely as an actor. If you want it to be a critic too, just add some expectations after the call to the factory method, although this is only really useful if you are testing Swift.

Code: Select all

<?php

class TestOfFoo extends AbstractTestWithSend
{
    public function testFoo()
    {
        $mock_conn = $this->getWorkingMockConnection(1);
        $mock_conn->expectAt(1, "write", array("MAIL FROM: <test@test.tld>", "*"));
        $swift = new Swift($mock_conn);
        $swift->send(new Swift_Message("xx", "yy"), "test@test.tld", "test@test.tld");
    }
}