Hi,
Maybe someone will be interested in what I came up with to test sending emails. Usually I use Mail::Mailer, but obviously I don't want to send real emails during testing - at best, they won't go anywhere, and at worst, they will go to real users and confuse them.
Now, I use in my code My::Mail::Mailer instead. It has the same API, and actually dispatches all the calls to the real Mail::Mailer if it's running in the production environment. However, if it's running tests, it dispatches all the calls to an instance of My::Mail::FakeMailer. In my code, testing and production environments are distinguished by the value of $ENV{SERVER_NAME}.
The FakeMailer class stores each email in a separate instance, which later can be accessed. For example, under the Test::Unit framework:
My::Mail::FakeMailer->flushInstances;
#Run code that sends emails...
my $mailer = My::Mail::FakeMailer->instances->[0];
$self->assert_equals('[EMAIL PROTECTED]', $mailer->hdrs->{To});
$self->assert_equals('[EMAIL PROTECTED]', $mailer->hdrs->{Cc});
$self->assert_equals('Correct subject', $mailer->hdrs->{Subject});I had to use IO::WrapTie to correctly catch filehandle-like access, so this is slightly non-trivial.
Any feedback is, of course, appreciated.
Simon --
Simon (Vsevolod ILyushchenko) [EMAIL PROTECTED]
http://www.simonf.comTerrorism is a tactic and so to declare war on terrorism is equivalent to Roosevelt's declaring war on blitzkrieg.
Zbigniew Brzezinski, U.S. national security advisor, 1977-81
package My::Mail::Mailer; #Tue Sep 7 10:55:11 EDT 2004 #Simon Ilyushchenko #In production environment call the real Mail::Mailer, in testing call FakeMailer.
use strict;
use Mail::Mailer;
use My::Mail::FakeMailer;
sub new
{
my ($class, @args) = @_;
my $instance;
if ($ENV{SERVER_NAME} eq "test")
{
$instance = My::Mail::FakeMailer->new_tie(@args);
}
else
{
$instance = new Mail::Mailer(@args);
}
return $instance;
}
1
package My::Mail::FakeMailer;
#Tue Sep 7 10:55:11 EDT 2004
#Simon Ilyushchenko
#Mimicking the normal Mail::Mailer so that we could test sending emails.
use strict;
use IO::WrapTie;
use base "IO::WrapTie::Slave";
my @instances;
sub instances
{
return [EMAIL PROTECTED];
}
sub flushInstances
{
my ($self) = @_;
@instances = ();
}
sub open {
my($self, $hdrs) = @_;
$self->{hdrs} = $hdrs;
}
sub close {
}
sub TIEHANDLE {
my $class = shift;
my $self = bless {}, $class;
push @instances, $self;
return $self;
}
sub PRINT {
my ($self, $string) = @_;
$self->{body} .= $string;
}
sub hdrs
{
my ($self, $val) = @_;
$self->{hdrs} = $val if $val;
return $self->{hdrs};
}
sub body
{
my ($self, $val) = @_;
$self->{body} = $val if $val;
return $self->{body};
}
1;
