12

I'd like to unit test a Perl program of mine that is using backticks. Is there a way to mock the backticks so that they would do something different from executing the external command?

Another question shows what I need, but in Ruby. Unfortunately, I cannot choose to use Ruby for this project, nor do I want to avoid the backticks.

Community
  • 1
  • 1
Jonas Wagner
  • 358
  • 3
  • 10
  • 1
    Can you clarify "I do not want to avoid the backticks"? – Ether Sep 09 '10 at 16:47
  • Vaguely related to this - I often write a things using system, or backtics then realise I want to check what command I am puitting out. I have thought of crating a diagnostic version of system. – justintime Sep 09 '10 at 16:50
  • @justintime: patching IPC::System::Simple to use a $DEBUG flag would be very welcome, I think. – Ether Sep 09 '10 at 17:03
  • 10
    You say "Ha Ha Ha, you are a stupid built-in." It annoys it to no end. – Chas. Owens Sep 09 '10 at 17:30
  • "nor do I want to avoid the backticks". Why do people care so much about the syntax they use? Why is it so important to use backticks over writing a couple more lines in a subroutine to do what you need, or even to use a module like Git::Wrapper? – brian d foy Sep 09 '10 at 18:34
  • @Ether, @brian d foy: I wrote this to clarify my requirements. The question would be rather easy to answer if "system" were used or some other method instead of backticks, because one can easily replace a built-in method (http://perldoc.perl.org/perlsub.html#Overriding-Built-in-Functions) Do I care much about the syntax? Not really... although programming is always a quest for the most beautiful solution. – Jonas Wagner Sep 10 '10 at 07:02
  • Why not just not use backticks? Or wrap backticks? – brian d foy Sep 10 '10 at 07:11
  • "Why not just not use backticks?"... what do you mean by that? – Jonas Wagner Sep 13 '10 at 07:54

2 Answers2

19

You can* mock the built-in readpipe function. Perl will call your mock function when it encounters a backticks or qx expression.

BEGIN {
  *CORE::GLOBAL::readpipe = \&mock_readpipe
};

sub mock_readpipe {
  wantarray ? ("foo\n") : "foo\n";
}

print readpipe("ls -R");
print `ls -R`;
print qx(ls -R);


$ perl mock-readpipe.pl
foo
foo
foo

* - if you have perl version 5.8.9 or later.

mob
  • 117,087
  • 18
  • 149
  • 283
  • This seems to only work right in later perls. 5.8.8 only prints foo for `readpipe(...)` and not backticks or `qx`. Works as shown in 5.10.1 – Eric Strom Sep 09 '10 at 19:46
  • Good catch Eric. This was changed in 5.8.9: http://search.cpan.org/~jesse/perl-5.12.2/pod/perl589delta.pod#readpipe_is_now_overridable – mob Sep 09 '10 at 19:59
2

Instead of using backticks, you can use capture from IPC::System::Simple, and then write a mock version of capture() in your unit test.

# application
use IPC::System::Simple qw(capture);
my $stuff = capture("some command");

# test script
{
     package IPC::System::Simple;
     sub capture
     {
         # do something else; perhaps a call to ok()
     }
}

# ... rest of unit test here
Ether
  • 53,118
  • 13
  • 86
  • 159