Devel::Cover recommendations... or maybe not?

Andy Armstrong andy at hexten.net
Thu Mar 15 15:42:39 GMT 2007


On 15 Mar 2007, at 15:17, Tara Andrews wrote:
> On 3/15/07, Pete Sergeant <pete at clueball.com> wrote:
>
>> and perhaps you have to occasionally tie yourself in
>> knots trying to hit certain failure conditions (especially file- 
>> system
>> error ones),
>
> OK, I'll bite.  How?
>
> Seriously, a list of hints somewhere of "how to programmatically
> manufacture useful sets of edge cases" would be very useful to people
> who want complete testing for their software, but don't have a wizzo
> tester to get us from A to B.

To test hard to simulate failures there's a simple old technique you  
can use. I first saw it in C but it works just as well in Perl.

Say you want to find out what happens when each of a number of malloc 
() calls throughout a program fails. In C the logic around recovery  
from malloc() failures tends to be quite complex. The answer is to  
construct a test suite that exercises each malloc() at least once.  
The whole test run might call malloc(), say, 200 times.

To test the malloc failure handling logic replace the malloc calls  
with a wrapper like this:

static int fail_malloc = 1;

void *my_malloc(size_t size) {
     static int which_malloc = 0;
     if (++which_malloc == fail_malloc) {
         /* Simulate failure */
         return NULL;
     }
     return malloc(size);
}

Then you run the test 200 times incrementing fail_malloc each time.  
Assuming that the test is deterministic it'll make the same pattern  
of calls to malloc on each run (at least until one of them fails -  
then it might behave differently as a result of the failure). So at  
the end of your 200 runs you know with complete certainty that you've  
exercised every possible malloc failure in the program.

Depending on how complex the logic is you might also want to cover  
various combinations of failures .e.g. what happens if all mallocs()  
after the 17th fail? If every other malloc fails? If possible it's  
better to design the code so that multiple failures on successive  
calls to malloc() are unlikely to interact with each other.

The same technique can be used with Perl to, e.g., simulate failure  
of a filesystem call. Replace the functions you want to watch with  
debug versions that can be set to fail after a certain number of  
invocations and then run the test repeatedly until you've exercised  
all the possible failures.

In general that's the kind of thing you need to do to get coverage of  
this-never-happens-but-we-need-to-handle-it-in-case-it-ever-does cases.

-- 
Andy Armstrong, hexten.net



More information about the london.pm mailing list