ambrus has asked for the wisdom of the Perl Monks concerning the following question:

In a perl module, I'd like to have two tests that are almost the same but differ a little bit in a setting. These should be ran independently (in two different perl interpreter invocations) because I'm changing the global state of the interpreter in a way that would be hard to undo, and I would not like the tests to interfere with each other. Also, even if either test fails completely or is skipped (eg. because some dependency is missing), the other should still be ran normally. If possible, I'd like the tests to work no matter how you invoke them, eg. make test (the makefile is generated by ExtUtils::MakeMaker), prove, or running the *.t files with perl directly.

Is there a best practice to do this kind of code sharing among two tests?

Update: mst claims the standard approach is to put the libraries for tests in the t/lib directory, and says that you always run tests with the working directory being the parent of t, so if you add use lib t/lib; to the tests that should find this modules.

Replies are listed 'Best First'.
Re: Share code among tests
by ikegami (Patriarch) on May 08, 2011 at 17:16 UTC

    Put your shared code in inc/<something>.pm and place the following in your .t:

    use Cwd qw( realpath ); use File::Basename qw( dirname ); use lib dirname(realpath($0)).'../inc';
Re: Share code among tests
by JavaFan (Canon) on May 08, 2011 at 17:05 UTC
    Uhm, do whatever you normally do when sharing code? Put it in a module and use the module?

      Yes, the shared code should probably be in a module (.pm) file, but in what directory should I put that file and possibly what options should I give to ExtUtils::MakeMaker. The tests should find this module file no matter how I invoke the tests, but the file should not be installed by make install.

        I typically put such files in the t directory, and start the test files with something like:
        BEGIN { chdir '..' unless -d 't'; } use t::Whatever;
        or
        BEGIN { chdir 't' if -d 't'; } use Whatever;
        or
        BEGIN { chdir '..' unless -d 't'; } push @INC, 't'; use Whatever;
        Now that only allows you to run the tests either from the 't' directory, or the top-level distro directory (using either "make test", "prove", or a path to the test file), but I've never felt the urge to run the tests from any other directory.
        t/lib is traditional. Put use lib 't/lib' at the top of the .t files so that they can find the shared code. You don't need to tell EU::MM anything special.
Re: Share code among tests
by Anonymous Monk on May 08, 2011 at 21:01 UTC
    To keep things organized, I'd use Test::Class for this. The part about 'EXTENDING TEST CLASSES BY INHERITANCE' may be useful. Your shared code would subclass Test::Class and your tests would in turn subclass that. Depending on your tests, you may only need to provide setup and teardown methods in your actual test files.
Re: Share code among tests
by ikegami (Patriarch) on May 08, 2011 at 17:04 UTC

    [ Nevermind, this isn't what you want. ]

    Perl's own test suite has a function called fresh_perl which runs the test in a new process. I don't think it's been placed in a Test:: module, but you can grab the function from the perl.