Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible use or require a Perl script without executing its statements?

I need to add unit testing to some old scripts, the scripts are all basically in the following form:

#!/usr/bin/perl

# Main code
foo();
bar();

# subs
sub foo {

}
sub bar {

}

If I try to 'require' this code in a unit test, the main section of the code will run, where as I want to be able to just test "foo" in isolation.

Is there any way to do this without moving foo,bar into a seperate .pm file?

like image 444
Matthew Watson Avatar asked Oct 24 '08 04:10

Matthew Watson


People also ask

What is require function in Perl?

Description. This function then it demands that the script requires the specified version of Perl in order to continue if EXPR is numeric. If EXPR or $_ are not numeric, it assumes that the name is the name of a library file to be included. You cannot include the same file with this function twice.

How is Perl executed?

You can enter Perl and start coding right away in the interactive interpreter by starting it from the command line. You can do this from Unix, DOS, or any other system, which provides you a command-line interpreter or shell window.

Do file in Perl?

Description. This function when supplied a block, do executes as if BLOCK were a function, returning the value of the last statement evaluated in the block. When supplied with EXPR, do executes the file specified by EXPR as if it were another Perl script.


2 Answers

Assuming you have no security concerns, wrap it in a sub { ... } and eval it:

use File::Slurp "read_file";
eval "package Script; sub {" . read_file("script") . "}";

is(Script::foo(), "foo");

(taking care that the eval isn't in scope of any lexicals that would be closed over by the script).

like image 141
ysth Avatar answered Oct 15 '22 03:10

ysth


Another common trick for unit testing scripts is to wrap the body of their code into a 'caller' block:

#!/usr/bin/perl

use strict;
use warnings;

unless (caller) {
    # startup code
}

sub foo { ... }

When run from the command line, cron, a bash script, etc., it runs normally. However, if you load it from another Perl program, the "unless (caller) {...}" code does not run. Then in your test program, declare a namespace (since the script is probably running code in package main::) and 'do' the script.

#!/usr/bin/perl

package Tests::Script;   # avoid the Test:: namespace to avoid conflicts
                         # with testing modules
use strict;
use warnings;

do 'some_script' or die "Cannot (do 'some_script'): $!";

# write your tests

'do' is more efficient than eval and fairly clean for this.

Another trick for testing scripts is to use Expect. This is cleaner, but is also harder to use and it won't let you override anything within the script if you need to mock anything up.

like image 33
Ovid Avatar answered Oct 15 '22 03:10

Ovid