Question

I want to test a script I have written in Perl and specifically check what output it writes to file. I wrote it some time ago and don't want to modify it to the extent of turning it into a module but would like to regression test it before adding some small functional changes.

So far I have

use Test::Command tests => 10;

exit_is_num($cmd, 0);
....

But the command produces some files and I want to check those files are the same as I expect (either equal or match some regexp). Any suggestions

Was it helpful?

Solution

There's nothing magic about a test. Read the files in, check they have the right contents. Bog simple.

open my $fh, $file;
my $have = join '', <$fh>;

is $have, <<'WANT', "contents of $file";
The quick brown fox
jumped over the lazy grey dog.
WANT

Nothing ground breaking there. Test::File::Contents will provide you with some utility functions so you don't have to write that over and over again.

If you're testing a bunch of files, you can make the process data driven.

my %file_tests;
$file_tests{"expected_filename"} = <<'WANT';
Expected content
WANT
... and so on ...

for my $file (keys %file_tests) {
    my $want = $file_tests{$file};

    file_contents_is($file, $want, "contents of $file");
}

If the contents are large you may want to stick the expected output into files and use files_contents_identical().

Finally, if you want to make sure the program ONLY produced the files you expect and there are no strays, make a temp directory, chdir into that, run the program from there, and check the directory only contains the files you expect. I'll leave that as an exercise for the reader.

OTHER TIPS

OK, I'll go with the brute force DIY approach (however it's possible there's already some test module with file checking API - I just never bumped into one as flexible/generic as what we needed and wrote ourselves and never felt the compelling need to search deeper :).

I'll describe a fairly generic testing setup, you may want/need only very specific file testing aspects of it.

What we do in this case is literally what your functional spec above states, as part of overall testing framework:

  • Have a testing library with two methods (among others) - test_file_identical() and test_grep_file(). If you need help writing those two, please drop a comment and i'll offer some hints (we use different comparators, including a combination of -e, comparisons of various stat attributes, comparing content strings of tested file vs. benchmark file obtained via File::Slurp and doing grep of the file, line by line or via slurped contents for small files, including comparison of massaged grep results to a benchmark file.

  • Have your tests cases organized into sub-directories (or tarballs), one per test, and each test consists of 2 directories - input files and expected output files.

  • Have the test engine script loop over test cases (which for us are meta-described either by a Perl datastructure or better yet, an XML file so business analysts can fiddle with them if needed).

  • If a test case specifies that the test needs to match (exactly or via grep), the test engine finds appropriate files (either hard-coded names, or via name pattern specified in test case), apply those file testing methods mentioned in the first bullet point

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow