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;

Reply via email to