lackita has asked for the wisdom of the Perl Monks concerning the following question:

I've got a test harness that captures emails by overriding the subroutine MIME::Lite::send. This works brilliantly about 90% of the time.

Unfortunately, I sometimes need to test subroutine Foo, which happens to have a system call and so my override loses its effect. If I'm calling the system call directly, I've got a module with an import method that can create the override using -M, but in the case where it's buried inside Foo that's not possible.

Does anybody know of a way that the override can persist into a system call? Or alternatively, a different method for capturing email in a test framework.

Replies are listed 'Best First'.
Re: Capturing Email During Testing
by mcdave (Beadle) on Jan 31, 2012 at 17:21 UTC
    About a different method for capturing email in a test framework... I've had great success (and fun) with "fakemail" http://www.lastcraft.com/fakemail.php. It sets up an SMTP server on localhost and anything that gets "mailed" to it ends up in a separate file in a directory of your choosing.

    I just have the following two line in my code and I toggle the comment depending on whether I'm testing or not:

    MIME::Lite->send( smtp => 'real.smtp.server.net' ) ; # MIME::Lite->send( smtp => 'localhost:10025' ) ;
    If you can't toggle the comments, you can change the network. Add an entry in /etc/hosts (or whatever your equivalent is) so "real.smtp.server.net" resolves to localhost and use fakemail running on port 25.

    Although that might just confirm: "There's more than one way to do it" doesn't always mean there's more than one way you should do it.

Re: Capturing Email During Testing
by GrandFather (Saint) on Jan 31, 2012 at 19:35 UTC

    I'm not sure what the "system call" has do do with your issue (you don't show any sample code), but maybe the following will give you a different tool to play with:

    #!/usr/bin/perl use strict; use warnings; use Test::MockObject; BEGIN { my $mockMIMELite = Test::MockObject->new(); my %params = (To => 'parp', Subject => 'Beep', From => 'Bop'); $mockMIMELite->fake_module( 'MIME::Lite', new => sub {ML_new($mockMIMELite, @_)}, send => sub { }, ); $mockMIMELite->mock(send => \&ML_send); $mockMIMELite->mock(attach => \&ML_attach); } use MIME::Parser; my $msg = MIME::Lite->new( To => 'wibble@wobble', From => 'Bogus email source', Subject => 'Email test', Data => 'Email body', ); $msg->send(); sub ML_new { my ($mock, $class, %params) = @_; $mock->{newParams} = \%params; return $mock; } sub ML_send { my ($self) = @_; my %fields = %{$self->{newParams}}; my @headerKeys = ( (grep {exists $fields{$_}} qw(To From Cc Subject)), (grep {!/^(data|subject|cc|to|from)$/i} sort keys %fields) ); print "--------------8<------------------\n"; print "$_: $self->{newParams}{$_}\n" for grep {defined $self->{newParams}{$_}} @headerKeys; print "Data:\n$self->{newParams}{Data}\n"; print "-------------->8------------------\n\n"; return 1; } sub ML_attach { my ($self, %params) = @_; my %fields = %{$self->{newParams}}; print ".............-8<..................\n"; print "Type: $params{Type}\n"; print "Path: $params{Path}\n"; print "Filename: $params{Filename}\n"; print "Disposition: $params{Disposition}\n"; print ".............-8<..................\n"; return 1; }

    Prints:

    --------------8<------------------ To: wibble@wobble From: Bogus email source Subject: Email test Data: Email body -------------->8------------------
    True laziness is hard work
Re: Capturing Email During Testing
by Anonymous Monk on Jan 31, 2012 at 14:41 UTC
    perlrun#PERL5OPT
    $ perl -le " print CGI->version " Can't locate object method "version" via package "CGI" (perhaps you fo +rgot to load "CGI"?) at -e line 1. $ set PERL5OPT=-MCGI $ perl -le " print CGI->version " 3.59
Re: Capturing Email During Testing
by pklausner (Scribe) on Feb 01, 2012 at 10:53 UTC
    If you are using Unix and you can configure you software to use local email addresses, then /etc/aliases is your friend. Just list what you want to do with your destination email address:
    thisname: /goes/to/file thatname: "| goes to a program" andthat: "|/bin/logger -p user.notice -t testmail" # goes to syslog