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

Greetings monkish ones,

I have a tiny little module (two methods and a class variable) that I need to write tests for. I'm thinking of making it a self-testing module such that if you just run it directly, it will run it's tests, but not if it is used/required into a script. I have two questions.

  1. Is this a good idea (or at least not a bad one)?
  2. What is a good way to determine when a module is being run directly? My first thought is to check %INC to see if the module name is mentioned there. Is there a more direct/reliable way to do this? Another way might be to examine $0, but that seems more messy.

--DrWhy

"If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

Replies are listed 'Best First'.
Re: Self-testing modules
by BrowserUk (Patriarch) on Jul 22, 2005 at 16:01 UTC

    package Foo; ... return 1 if caller; ## we're being called, stop here. ## Otherwise we're being run as 'perl Foo.pm', so test. package main; my $testObj = new Foo; ## test stuff.

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
      This solution will not allow you to use modules (or do other compile time work) cleanly. Any use statement (no statement, BEGIN block, END block, etc.) will always get executed no matter how the enclosing module is used.

      The previous method (__END__;#!perl + perl -x module.pm), while more cumbersome in some ways, lets you do compile time work as normal.

      --DrWhy

      "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

        Any use statement (no statement, BEGIN block, END block, etc.) will always get executed no matter how the enclosing module is used.

        That is true, so I don't do that. I don't use the Test::* modules as they tell me what passed rather than what failed. I also have very definite ideas about the form that unit testing should take and that does not fit well with the pattern of a zillion ok()/not_ok() tests that those modules encourage.

        If my test code needs additional modules, I require them not use them. On the rare occasions I've felt the need for BEGIN/INIT/CHECK/END blocks, they've been an inherent part of the module not the testcode.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
Re: Self-testing modules
by davidrw (Prior) on Jul 22, 2005 at 15:36 UTC
    first thought is that (while interesting) it probably isn't worth doing and would be better to stick with the stand ways of making a distribution/test suite, regardless of the simplicity (two methods and a class variable) of the module.

    that being said, for the sake of discussion, my immediate second thought (before reading that you had it) was to check $0 and compare it to __FILE .. though i think you're right and it might be messy (though maybe not).. might be easy if combined with File::Spec to convert any relative path to absolute.

    anyways, then another, and i think better, way pooped into my head:
    package Foo; ... __END__ #!/usr/bin/perl use Foo; # run tests here.
    This way you can use Foo; normally (or require, etc) from other scripts, but you can also do perl -x Foo.pm
Re: Self-testing modules
by DrWhy (Chaplain) on Jul 22, 2005 at 17:42 UTC
Re: Self-testing modules
by sgifford (Prior) on Jul 22, 2005 at 19:26 UTC
    I'm not convinced this is worth doing (using more standard test methods is pretty simple, and lets the user delete the test code once they've installed the module), but caller provides the information you need to determine whether you're inside of a use or require:
    #!/usr/bin/perl if (!(caller(0))[7]) { # Not inside of a use print "Running tests...\n"; } sub some_sub { print "Running some_sub\n"; } 1;