简体   繁体   中英

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

For example in the following code how do I mock readline to unit test the do_stuff routine?

I think I require

  1. $sock must be a GLOB reference.
  2. readline() must be mocked.

I tried using FileHandle->new but got error - "readline() on unopened filehandle GEN1" which I took as readline() wasn't being mocked.

I tried an Test::MockObject (not extends), with readline() mocked, but that had the error "Not a GLOB reference" which reminded me that readline() isn't being called as a method.

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';

}

You can use the following:

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

This won't work if a system file handle is needed (eg if the handle needs to survive an exec ). But as long as you stick to Perl, reads from the handle will read from the provided buffer.

Builtins like readline must be mocked in the CORE::GLOBAL namespace, and must generally be defined at compile-time.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM