Two-parter, both related to testing and module development:

First, how do others incorporate unit testing into their module work? The 'correct' way is to first write out the design of the code; then starting with the least user-code-dependant portion, write the testing code first, and THEN the module (eg, you write out it's usage, then you write the details of the function); unit test that particular piece of code, then continue to build on that until you've covered the entire code, making sure to unit test all previous code when adding new code to a project in case something has changed. Obviously this can be long and convoluted, but it should work. However, looking at much of the examples of perl modules out there, it would seem to me, at least, that testing is always a secondary feature that is completely written after the module is written for the first time. Has anyone gotten a reasonable approach for how to write test code for perl modules?

Second, when unit testing, particularly perl code, how much do you test? For example, say we have a simple function pythag($a,$b) which returns sqrt($a*$a+$b*$b). Given that a scalar can be a number of things, the code should check that $a and $b are valid numbers, and (optionally, but sake of example), $a and $b are positive numbers. Given this, there's at least three possible (4 many) numbers one can try for each: a negative number, zero, a small positive number, and a very large positive number (which when squared will overflow the maximum float value), for a total of 16 possibilities. But then you can consider the non-numericals; the empty value '', string scalars, and references. Obviously, in the code of the function, these can all be dealt with with a few if statments, but if you consider these 3 situations as 3 more cases to test, you're now at a total of 49 test situations, and you could easily extrapolate more. I would think at some point, there's a limit to what is overkill, but is there some practical point for this?

And I guess a bonus question: in testing modules that use DBI, is it first possible to figure out what DB server is installed and thus was DBI connect to provide, and is there a standard test database that one can use for DBI that can be assumed to be in place when the user ok's DBI testing, or should one just create and delete a new table when this step is done?

-----------------------------------------------------
Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
It's not what you know, but knowing how to find it if you don't know that's important

  • Comment on Unit Testing and Perl Module Development

Replies are listed 'Best First'.
Re: Unit Testing and Perl Module Development
by tommyw (Hermit) on Sep 20, 2001 at 18:38 UTC

    The pragmatic shortcut to the second point is to define a range of valid inputs, and to only ensure that the code works for that range.

    So, for your example, a reasonable initial definition would be "$a, $b are numbers". If the input does not comply with the specified criteria, then the user gets what they deserve (such as Argument "hello" isn't numeric in multiplication (*), if they've got warnings enabled.)

    That way, the developer doesn't have to waste time testing that behaviour, and possibly more importantly, the code doesn't have to waste time sanity checking its inputs. Of course, if it turns out that the function is frequently called with nonsensical parameters, then it does become worth guarding against. But in this specific case, it's reasonable to realise that the arguments should not be strings. Obviously, there are case where it's not so intuitive.

    Next you'll realise that I've reduced your test cases back down from 49 to 1. Hooray! Except that I'm wrong: large numbers will still cause potential problems. There are now two intepretations of this though: either there's an error in the code, or there's an error in the specification. In this case, it's probably easier to change the specification, to include the restriction that abs($a)<some value (such that the operation works). Then, when this condition is broken, the function is again free to do whatever it wishes. And it probably will :-) (This is a case, however, where it's probably worth the function actually checking it's inputs, so the specification can be extended with "and if these values are exceeded, then the function dies, in order to locate the erroneous call" unless part of the requirement is a low overhead.) By ensuring that $a and $b are treated symmetrically, we only have to add one test case. At least until we reach the point where both values are "quite large" so that the overflow happens at the addition stage, rather than multiplication.


    As for your bonus question, no, there's no guaranteed database available. Instead, you should look at DBI->available_drivers and DBI->data_sources to find out what's around.

Re: Unit Testing and Perl Module Development
by princepawn (Parson) on Sep 20, 2001 at 19:44 UTC
    I think the comprehensive test suite for DBIx::Recordset will answer all of these questions.
Re: Unit Testing and Perl Module Development
by miyagawa (Chaplain) on Sep 21, 2001 at 11:33 UTC