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

I have this question. I have a module and I create an anonymous function inside this module. This anonymous function is assign it to a lexical variable, aiming to make it a private function (no declaration in EXPORT or EXPORT_OK ...)
my $privateFunc = sub { ... }
Now, when I want to create a test case for this. I don't know how to declare such lexical variable in the test script, since it is supposed not to be access from outsider, including the test script.
Please help me, thanks.

Replies are listed 'Best First'.
Re: test case for private function in module
by Marshall (Canon) on Apr 05, 2009 at 06:24 UTC
    This idea of creating a "my" private variable as a sub ref to try to make a totally private function is a non-Perl idea, and not a good one. Perl assumes that you will conform to the interface spec. Or override it when you think it is necessary and proper.

    If you make sub privateFunction{} and do not export the name "privateFunction" then anyone following the interface will not be able to call it.

    If I know your module name and name of this sub, then even if the sub privateFunction() is not exported, I can call it with the fully qualified name YourModuleName::privateFunction();. Perl module I/F's keep "honest folks honest", but is possible to do "something not intended". Sometimes that's good and sometimes that bad.

    In Perl as in C,etc., there are various naming conventions for Private vs Public functions. You can put _, underscore for a private func as a clue that this is not intended for it to be called outside the I/F, but it still can be.

    There also appears to be a logical inconsistency in your test strategy. If this function is private, then NO external program should call it, including your test program. There should be a module test routine that tests that module(that test routine is part of the module). Your test program calls this test function, not in the private guts of the module itself. Your test function remains stable even in light of massive implementation changes within the module.

    One easy technique for testing is to make a standard sub in each module say "sub test()" and don't export that name. To test, call YourModuleName::test();

Re: test case for private function in module
by ikegami (Patriarch) on Apr 05, 2009 at 06:00 UTC
    Add the last bit of the following to your script:
    package Foo::Bar; my $privateFunc1 = sub { ... } my $privateFunc2 = sub { ... } my $privateFunc3 = sub { ... } if (our $TESTING) { # Expose private functions for testing. *_privateFunc1 = $privateFunc1; *_privateFunc2 = $privateFunc2; *_privateFunc3 = $privateFunc3; }

    By setting var $TESTING in your module's package to something true, you can now perform testing on your private functions.

    BEGIN { $Foo::Bar::TESTING = 1; } use Foo::Bar; is( Foo::Bar::_privateFunc1($val), $expect, 'privateFunc1' );

      Awesome! I have been stewing for several weeks over the almost exactly the same dilema...but was trying (probably too obsessively) to solve it on my own.

      I got frustrated but just decided to shelve it until I learned more.

      This is almost uncanny. Thanks to both minhtuanht and ikegami. Some days things just seem to rock!

      ack Albuquerque, NM
Re: test case for private function in module
by NetWallah (Canon) on Apr 05, 2009 at 04:32 UTC
    Change the my to our, then call it.
    use strict; use warnings; INIT{ package Mypackage; use strict; use warnings; our $privateFunc = sub { print "Private parts - do not touch\n"; } } # End of package #We are now OUTSIDE. $Mypackage::privateFunc->();

         ..to maintain is to slowly feel your soul, sanity and sentience ebb away as you become one with the Evil.

Re: test case for private function in module
by Anonymous Monk on Apr 05, 2009 at 03:08 UTC