views:

705

answers:

4

Hello!

I have written a small Perl script and now I would like to create a test suite for it. I thought it would be nice to be able to use the script as a module, import the subs defined in the script and test these. Is there a way to have the script both standalone Perl script and Perl module? (I do not want to split the script into a separate module and the “executable”, since I plan to distribute the script as a single file.)

Or is there a better way to test the script?

A: 

Why not writing a test suite in a shell script, with the Perl script called like any other shell command ?

mouviciel
Yes, that’s surely an option, but using the subs directly seems much more convenient to me.
zoul
+3  A: 

(I do not want to split the script into a separate module and the “executable”, since I plan to distribute the script as a single file.)

Most people stitch files together like this at build time. App::Ack on the CPAN is an example of something that can be built like this.

If you really want to test your application properly, you need to put the functionality in a module, and then write a Test::More-based test script that exercises the functions that the module provides. Then the actual script is just a thin wrapper around the module, usually something like:

#!/usr/bin/env perl
use Your::Class;
Your::Class->new(args => \@ARGV)->run;

See also: MooseX::Getopt.

jrockway
+1  A: 

It depends on whether you want to test the script itself, or test the subs that make up the script. If you want to test the script, then an external test would be more appropriate, e.g. a shell script. If you want to test the functions that make up the script, then you can either write those tests as more functions within the script or refactor the elements into a Perl module and test the module (which you say you don't want to do).

If the script is small enough, then refactoring might not be necessary. Simply add a '-test' command line argument and call into a test sub, which in turn tests everything else. If doing this, I like to print out a progress indicator of some kind (e.g. a '.' for every test that passes).

If the script is more complex, though, you may want to consider refactoring bits into one or more modules and testing them with Test::Simple or Test::More.

Joe Casadonte
+12  A: 

Since brian seems to be asleep right now, here's a pointer to what he calls modulinos. This is basically a recipe for building scripts that act like modules or modules that can be run like scripts. Sounds exactly like what you are looking for.

Mastering Perl is definitely a book worth reading (and buying).

innaM
Thank you, this is exactly what I was looking for.
zoul
I think there is a convenience in making a module act like a script, but I don't see the value in making a script act like a module. At least not yet....
Joe Casadonte
The answer is in the question (not your question, but the original one). It is much easier to unit-test a module than to unit-test a script
innaM
Not asleep, just working :) The advantage of having a script as a module is that you can break it into pieces for unit testing. Otherwise, you only get to run the whole script.
brian d foy
Nice. This helped me.
Paul Nathan
This is great! I've been wondering how to do this.Would it also be valid to name a script with a .pl extension, and put this line in the top: "return 1 if ( caller() );" That way, the script can run normally, and then my testing script can "require 'myscript.pl'" and test each function. Or is that bad practice?
BrianH