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.com
Terrorism 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;