I am trying to test a script that I'm including in my Perl distribution. The script only outputs to files, so my tests check file contents after running it. I tried following the directions in this post, but it doesn't quite work for me. The script that I'm testing uses a module in the same distribution, so running the script requires the location of the module to be added to @INC somehow. I noticed that Test::Script adds -Mblib to the arguments, so I tried the same. However, it wouldn't work during development because there was no blib directory. Using -Mblib makes everything work only under dzil test or make test. While developing, I use either prove or simply perl -Ilib t/test_script.pl, and trying to use -Mblib results in failed tests and the warning Cannot find blib even in C:\. Considering this, I have a few lines of code that are missing one crucial piece:

my $script_path = catfile( $FindBin::Bin, updir(), qw(scripts my_script.pl) );
my $include = 
    $HAS_BLIB && '-Mblib' || 
    '-I"' . catdir($FindBin::Bin, updir(), 'lib') . '"';
my $args = join ' ', map {qq["$_"]} @input_args;
my $command = qq{"$^X"  $include "$script_path" $args};
`$command`;
#test that script worked here...

What do I put instead of the scalar $HAS_BLIB? I need a way to tell if I'm in the middle of building the distribution or not. Other input is welcome. Maybe there's a better way for me to go about doing this? I'd just like a way to test the script that passes with both prove and make test.

有帮助吗?

解决方案

To answer the question, you can use Module::Path to check if any of the module files in the distribution are in a blib/lib directory. This is not foolproof because someone might be running prove on the distribution inside another directory called blib, but I think that's unlikely. This also has the disadvantage of requiring that the distribution has a .pm file in it somewhere, which may not be the case.

Alternatively, you could check to see if the directory holding the t directory (in a test script this would be $Bin from FindBin) has a blib directory in it. However, if you've run make without make clean and then further developed the script, when you run prove the stale script in the blib directory will still be run.

In my comment on my question I mentioned checking $INC{'blib.pm'}. This only works if the test script was called with -Mblib, and make test does not do that. Instead it calls ExtUtils::Command::MM::test_harness with blib/lib and blib/arch as include directories.

Once you know that you're running code out of blib, then you need to change both the include path, which should be blib/lib, and the script path, which should be blib/script/whatever (and no .pl if your script had one originally, because make removes it). So here's a correct version of the original example:

use Module::Path 'module_path';
use Path::Tiny;
use FindBin;
use Test::More;
plan tests => 1;
use Capture::Tiny;
my $module_path = path(module_path('My::Thing'));
my $HAS_BLIB =
    $module_path        #Thing.pm
        ->parent    #My
        ->parent    #lib
        ->parent    #blib
        ->basename eq 'blib';
my $script_path = $HAS_BLIB && path(qw(blib script my_script)) ||
    path(path($FindBin::Bin)->parent, 'bin', 'my_script.pl');
my $include = $HAS_BLIB && '-Mblib' || # could also do -Iblib/lib -Iblib/arch
    '-I'. path(path($FindBin::Bin)->parent, 'lib'); # would use installed version of C code
my @command = ($^X, $include, $script_path, @batch_files);
my ($stdout, $stderr) = capture {system(@command)};
is($stderr, '', 'no errors reported from script');
#more tests here

This is an awful lot of trouble, and in this case I don't think that it's necessary. I'm not entirely sure when it would be useful. If your distribution has C/C++ code then you might want to always use the blib solution, which adds blib/arch to the include path. With the above simple example, the test passes using the non-blib settings because the original files are still available. Little change happens to the files copied into the blib directory. So when I was debugging this, the only way I could tell if it was doing the right thing was to print out the full command used!

In other words, it wasn't very testable, and if someone really needs this then they should create a module to manage it (and test that). Test::Script seems to always use -Mblib, which would mean you could be using a stale make result, and you have to pass in the path of the script, meaning it's up to you to decide to whether to use the original script or the one inside blib/script.

其他提示

If you just need to test that the script has successfully written to files and don't need to check their contents, you can do that within the script. Perl open, for example, returns nonzero on success, and print returns true if successful.

Capture the return values of those functions (or whatever you are using), test for success, and set your script's exit value accordingly, then test on that.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top