如何对打印到屏幕的Perl函数进行单元测试?

tom*_*dee 34 testing perl unit-testing

我正在尝试使用Test :: More来测试打印到屏幕的Perl函数.

我知道这个输出可能会干扰诸如证明之类的工具.

如何捕获此输出以便我可以打印它diag(),并在输出本身上运行测试?

Sin*_*nür 32

更新:恕我直言,这个问题的正确答案应该是使用Test :: Output:

#!/usr/bin/perl

use strict; use warnings;

use Test::More tests => 1;
use Test::Output;

sub myfunc { print "This is a test\n" }

stdout_is(\&myfunc, "This is a test\n", 'myfunc() returns test output');
Run Code Online (Sandbox Code Playgroud)

输出:

C:\Temp> tm
1..1
ok 1 - myfunc() returns test output

我将离开原始答案以供参考,我相信,它仍然说明了一种有用的技术.

STDOUT在调用函数之前,您可以本地化并重新打开标量,然后恢复:

#!/usr/bin/perl

use strict; use warnings;

use Test::More tests => 1;

sub myfunc { print "This is a test\n" }

sub invoke {
    my $sub = shift;
    my $stdout;
    {
        local *STDOUT;
        open STDOUT, '>', \$stdout
            or die "Cannot open STDOUT to a scalar: $!";
        $sub->(@_);
        close STDOUT
            or die "Cannot close redirected STDOUT: $!";
    }
    return $stdout;
}

chomp(my $ret =  invoke(\&myfunc));

ok($ret eq "This is a test", "myfunc() prints test string" );
diag("myfunc() printed '$ret'");
Run Code Online (Sandbox Code Playgroud)

输出:

C:\Temp> tm
1..1
ok 1 - myfunc() prints test string
# myfunc() printed 'This is a test'

对于perl早于5.8的版本,您可能需要使用IO :: Scalar,但我不太了解5.8之前的工作原理.

  • 就在我认为我浪费太多时间的时候,我学到了很多东西!谢谢. (4认同)

mpe*_*ers 7

我想看看让模块为你处理这个问题.看看Capture :: Tiny.


bri*_*foy 6

如果这是您自己编写的代码,请更改它以使print语句不使用默认文件句柄.相反,给自己一个方法将输出文件句柄设置为你喜欢的任何东西:

sub my_print {
     my $self = shift;
     my $fh = $self->_get_output_fh;
     print { $fh } @_;
     }

sub _get_output_fh { $_[0]->{_output}  || \*STDOUT }
sub _set_output_fh { $_[0]->{_output} = $_[1] } # add validation yourself

当你测试时,你可以调用_set_output_fh它给你的测试文件句柄(甚至可能是一个IO :: Null句柄).当另一个人想要使用你的代码但是捕获输出时,他们不必向后弯腰来执行它,因为他们可以提供他们自己的文件句柄.

当您发现代码的一部分难以测试或者您必须跳过箍来使用时,您的设计可能很糟糕.我仍然对测试代码如何使这些事情变得明显感到惊讶,因为我经常不会考虑它们.如果难以测试,请轻松测试.如果你这样做,你通常会赢.