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

Monks, I am becoming a test junkie. I wanna test everything!

One thing I still haven't figured out how to test is, if you have a function that only prints output but doesn't return anything. Can someone teach me how to make this print "ok 1, ok 2"?

use strict; use warnings; use Test::More qw(no_plan); my $status = Status->new(); #how do I test this? $status->status('good'); # should be "ok" if the right message got pri +nted $status->status('bad'); # should also be "ok" if the right warning got + printed package Status; sub new { my $package = shift; my $self = {}; bless $self, $package; } sub status { my $self = shift; my $status = shift; if ($status eq 'good') { print "good status\n"; } else { warn "bad status\n"; } } 1;

Replies are listed 'Best First'.
Re: How do you Test that the right output got printed?
by brian_d_foy (Abbot) on Jul 27, 2005 at 18:49 UTC

    It sounds like you want Test::Output. Whenever you have a question about how to test something, check the list of Test::* modules. There's probably one that does it for you already.

    --
    brian d foy <brian@stonehenge.com>
Re: How do you Test that the right output got printed?
by adrianh (Chancellor) on Jul 27, 2005 at 18:51 UTC

    Test::Output can help. For example (untested):

    use strict; use warnings; use Test::More tests => 2; use Test::Output; my $status = Status->new(); stdout_is { $status->status('good') } "good status\n"; stdout_is { $status->status('bad') } "bad status\n";
Re: How do you Test that the right output got printed?
by blokhead (Monsignor) on Jul 27, 2005 at 18:28 UTC
    In terms of good design, the previous replies are right on the money. But if you are unable to restructure your code as they suggest, it is still possible to test what you are asking.

    You can localize STDERR and STDOUT to filehandles which write to scalars. Then call the method and check that the scalars contain what they should:

    use Test::More 'no_plan'; my $status = Status->new; my ($stderr, $stdout); { local(*STDERR, *STDOUT); open STDERR, ">", \($stderr = ""); open STDOUT, ">", \($stdout = ""); $status->status("good"); } ok( ($stderr eq "") and ($stdout =~ /good status/) ); ### { local(*STDERR, *STDOUT); open STDERR, ">", \($stderr = ""); open STDOUT, ">", \($stdout = ""); $status->status("bad"); } ok( ($stderr =~ /bad status/) and ($stdout eq "") );

    blokhead

Re: How do you Test that the right output got printed?
by jeffa (Bishop) on Jul 27, 2005 at 18:05 UTC

    You use one of the Test methods, and return a value from your sub/method instead of printing to STDOUT or STDERR:

    use Test::More qw(no_plan); my $status = Status->new(); is ($status->status('good'), 'good'); is ($status->status('bad'), 'good'); package Status; sub new { my $package = shift; my $self = {}; bless $self, $package; } sub status { my $self = shift; my $status = shift; if ($status eq 'good') { return "good"; } else { return "bad"; } }
    I don't recommend having a method print directly -- let the client do the printing.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: How do you Test that the right output got printed?
by mrborisguy (Hermit) on Jul 27, 2005 at 18:18 UTC

    Like jeffa said, you want status to return a value instead of printing. This not only makes it better for testing, but it's better OO practice in general. What if some time along the line, somebody wants to subclass your class, and wants to know the status. You're forcing them to print it out, but if you just return a value, then it's useable to them. Also it's not too much difficult, and more clear, to write:

    print $status->status('good'); # instead of $status->status('good');

        -Bryan

Re: How do you Test that the right output got printed?
by kwaping (Priest) on Jul 27, 2005 at 18:09 UTC
    I can't think of a good reason to have a method that doesn't have a return value, except maybe a little less typing for the developer. If you don't care what the return value is, just don't check it outside of your test suite.

    Personally, I like the first reply best - just return the value to be printed and do your printing outside the sub. That will give the method-user the most flexibility in how they incorporate that method into their own programs.