答案 0 :(得分: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');
输出:
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'");
输出:
C:\Temp> tm 1..1 ok 1 - myfunc() prints test string # myfunc() printed 'This is a test'
对于早于5.8的perl
版本,您可能需要使用IO::Scalar,但我对5.8之前的工作原理不太了解。
答案 1 :(得分:7)
我会考虑让模块为您处理这个问题。请看Capture::Tiny。
答案 2 :(得分: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句柄)。当另一个人想要使用你的代码但是捕获输出时,他们不必向后弯腰来执行它,因为他们可以提供自己的文件句柄。
当您发现代码的一部分难以测试或者您必须跳过箍来使用时,您的设计可能很糟糕。我仍然对测试代码如何使这些事情变得明显感到惊讶,因为我经常不会考虑它们。如果难以测试,请轻松测试。如果你这样做,你通常会赢。