Как было указано в новых требованиях, приложение должно оповещать администратора при появлении нового сообщения. Сделать это несложно, вопрос лишь в том, как можно это правильно протестировать? Дело в том, проверить обычными средствами отсылку письма довольно-таки сложная задача. На помощь нам придет пакет FakeMail(http://sourceforge.net/projects/fakemail), находящийся в разработке.
FakeMail эмулирует работу почтового сервера и складывает всю приходящую почту в заданное пользователем место. Таким образом, можно проконтролировать из теста все обращения к почтовому серверу. Центральной частью FakeMail является perl скрипт, запускаемый в режиме демона на определенном порту. Также в состав пакета входит класс FakeMailDaemon, удобным образом инкапсулирующий работу с perl сервером.
Чтобы запустить FakeMailDaemon в Windows, требуется наличие библиотеки cygwin, а именно интерпретатора perl, входящего в состав cygwin. Внимание: ActiveState Perl не работает с FakeMail.
Предположим для простоты, что вся уведомляющая почта доставляется на ящик admin@feedback.com. Изменим наши фукциональные тесты немного, заменим метод testOfSimpleSubmitFeedback на testOfSimpleSubmitFeedbackWithEmailNotification:
<?php
class AcceptanceTestOfFeedbackProject extends WebTestCase {
function setUp() {
DBC :: execute('DELETE FROM feedback');
$this->_switchToWebTestingConfig();
$this->fakemail = new FakeMailDaemon();
$this->fakemail->start();
}
function tearDown() {
$this->_switchToProductionConfig();
$this->fakemail->stop();
$this->fakemail->removeRecipientMail('admin@feedback.com');
}
function testOfSimpleSubmitFeedbackWithEmailNotification() {
$this->_addFeedback($name = 'Bobby',
$email = 'email@dot.com',
$message = "This a message");
$this->assertWantedPattern('/' . preg_quote($email) . '.*' .
$name . '.*' .
$message . '/s');
$mails = $this->fakemail->getRecipientMailContents('admin@feedback.com');
$this->assertTrue(sizeof($mails) == 1);
$this->assertTrue(preg_match('~' . preg_quote($email) . '.*' .
$name . '.*' .
$message . '~s',
$mails[0]));
}
[...]
}
?>
Отметим, что нам также пришлось изменить фикстуру, теперь в ее обязанности также входит запуск/остановка FakeMailDaemon и очистка пришедшей почты.
Нам также пришлось добавить следующую строку в /tests/setup.php:
<?php
define('FAKE_MAIL_DUMP_PATH', dirname(__FILE__) . '/mail/');
?>
С помощью нее мы указали FakeMailDaemon сохранять всю временную почту в директории /tests/mail.
Как всегда, тест не сработал... теперь приступаем к реализации.
Для отправки писем воспользуемся замечательным пакетом PHPMailer. Создадим небольшую глобально доступную фабричную функцию CreateMail() в файле mail.inc.php, которая будет скрывать детали инициализации phpmailer:
<?php
@define('USE_PHPMAIL', false);
@define('SMTP_PORT', '25');
@define('SMTP_HOST', 'localhost');
@define('SMTP_AUTH', false);
@define('SMTP_USER', '');
@define('SMTP_PASSWORD', '');
function & CreateMail()
{
include_once(dirname(__FILE__) . '/external/phpmailer/class.phpmailer.php');
$mail = new PHPMailer();
$mail->LE = "\r\n";
if(USE_PHPMAIL)
return $mail;
$mail->IsSMTP();
$mail->Host = SMTP_HOST;
$mail->Port = SMTP_PORT;
if(SMTP_AUTH == true)
{
$mail->SMTPAuth = true;
$mail->Username = SMTP_USER;
$mail->Password = SMTP_PASSWORD;
}
return $mail;
}
?>
Теперь можно перейти к реализации в index.php:
<?php
ob_start();
require_once(dirname(__FILE__) . '/external/wact/framework/common.inc.php');
require_once(WACT_ROOT . '/template/template.inc.php');
require_once(dirname(__FILE__) . '/feedback.inc.php');
require_once(dirname(__FILE__) . '/mail.inc.php');
if(isset($_POST['submit'])) {
$feedback = new Feedback($_POST['name'], $_POST['email'], $_POST['message'], $time = time());
$feedback->save();
$mail =& CreateMail();
$mail->IsHTML(false);
$mail->CharSet = 'windows-1251';
$mail->AddAddress('admin@feedback.com');
$mail->From = $_SERVER['SERVER_ADMIN'];
$mail->FromName = $_SERVER['HTTP_HOST'];
$mail->Subject = 'New feedback!!!';
$mail->Body = $_POST['email'] . "\n" . $_POST['name'] . "\n" . $_POST['message'];
$mail->Send();
}
$page = new Template('/feedback.html');
$pager =& $page->getChild('pager');
$feedback =& $page->findChild('feedback');
$feedback->registerDataSet(Feedback :: getList($pager));
$page->display();
ob_end_flush();
?>
Вот теперь, пожалуй, все. Не так уж и плохо для первого раза.