在 perl 中进行单元测试时,如何模拟 GLOB ref 的真实行?

How do I mock a realine of a GLOB ref when unit testing in perl?

例如,在下面的代码中,我如何模拟 readline 以对 do_stuff 例程进行单元测试?

我想我需要

  1. $sock 必须是 GLOB 引用。
  2. readline() 必须被模拟。

我尝试使用 FileHandle->new 但出现错误 - “readline() on unopened filehandle GEN1” 我认为 readline() 没有被嘲笑。

我尝试了 Test::MockObject(不是扩展),并模拟了 readline(),但出现了错误 “不是 GLOB 引用”提醒我 readline() 没有作为方法调用。

package MyIO;

sub get_sock{ return IO::Socket::INET->new(@tcp_arg); }

sub do_stuff {
    my $sock = get_sock();
    my $line1 = <$sock>;
    my $line2 = readline($sock);
    return;
}

package TestMyIO;

sub test_do_stuff{
    # my $mock_sock = Test::MockObject::Extends->new(IO::Socket::INET->new);

    my $mock_sock = die("TODO");
    my @fake_lines = ('line 1', 'line 2', 'line 3');

    no warnings 'redefine';    ## no critic (ProhibitNoWarnings)
    local *MyIO::get_sock = sub { return $mock_sock; };
    local *MyIO::readline = sub { return shift @fake_lines; };
    use warnings 'redefine';

}

您可以使用以下内容:

open(my $fh, '<', $str);

如果需要系统文件句柄(例如,如果句柄需要在 exec 中存活),这将不起作用。但是只要您坚持使用 Perl,从句柄中读取的内容就会从提供的缓冲区中读取。

readline 这样的内置函数必须在 CORE::GLOBAL 命名空间中模拟,并且通常必须在编译时定义。

my @fake_lines;
BEGIN {
    *CORE::GLOBAL::readline = sub { shift @fake_lines };
}
@fake_lines = ('line 1','line 2','line 3');