Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

Re: Needing help on testing

by roboticus (Chancellor)
on Oct 29, 2018 at 21:56 UTC ( #1224888=note: print w/replies, xml ) Need Help??

in reply to Needing help on testing


You could always try adding a command-line option to invoke a test routine and quit instead of running normally. Suppose, for example, you have the following program:

#!env perl # # <Number> # # Print the list of prime factors for Number # # 20130206 Can't find a copy on my hard drive, so making it again use strict; use warnings; my $num = shift or die "Expected number to factor!"; print "$num: ", join(", ", factors($num)), "\n"; sub factors { my $val=shift; return unless $val; my @primes = (1); if ($val < 0) { unshift @primes, -1; $val = -$val; } while ($val % 2 == 0) { push @primes, 2; $val = $val/2; } my $fac=3; while ($fac*$fac <= $val) { while ($val % $fac == 0) { push @primes, $fac; $val = $val / $fac; } $fac += 2; } push @primes, $val if $val > 1; return @primes; }

Suppose further that you wanted to make sure that the factors routine was tested. You could create a routine with some tests like this:

sub do_tests { use Test::More; use Data::Dump 'pp'; my @test_cases = ( [ 0, [] ], [ 1, [1] ], [ 2, [1, 2] ], [ 3, [1, 3] ], [ 4, [1, 2, 2] ], [ -72, [-1, 1, 2, 2, 2, 3, 3] ], ); for my $case (@test_cases) { my @f = factors($case->[0]); # Uncomment for debugging #print "$case->[0], exp: (", join(",",@{$case->[1]}), "), got( +", join(",",@f),")\n"; is_deeply([@f], $case->[1]); } done_testing(); }

and then change the line that calls it and prints the results to this:

if ($num eq "-test") { do_tests(); } else { print "$num: ", join(", ", factors($num)), "\n"; }

So now, I can either use the program normally, or test it:

$ perl 1234 1234: 1, 2, 617 Roboticus@Waubli ~ $ perl -test ok 1 ok 2 ok 3 ok 4 ok 5 ok 6 1..6

Unfortunately, a lot of code that was written without tests can be tricky to test. Writing code with tests tends to change your coding style to make your code more testable. So while this trick may help you on your way to starting to get some of your code tested, be aware that retrofitting tests to code you currently have can be a bit tricky.

I'd suggest trying to add testing where you can, though, as it can make your code better. I don't see any problems with using a trick like this as a starting point.

In fact, when writing this response, I found a couple cases where my factors routine didn't work. It had an infinite loop if you gave it 0 (it would keep adding '2' to the factors while checking for even numbers), and I didn't make it work for negative numbers at all. The act of me coming up with a few simple test cases made me find and fix those bugs. This little thing has been on my computer for over five years, and I hadn't encountered a problem with it yet. (Not surprising, as I wouldn't call this script to factor 0 or a negative number. But had I moved factors() into one of my libraries and assumed it was fully tested, it would have been found wanting the first time it tried factoring a negative number or 0.

Another nice thing about test cases is that they can provide some basic documentation on how to use the function, should the comments be inadequate. For example, I should probably return 1, 0 for the factors of 0, but for my purposes, I prefer an empty list, so I'm leaving it that way. If I decide to reuse factors() for another purpose, the result for 0 should be obvious from the test, and I can change the code accordingly if I want 1, 0 in the other use case(s).


When your only tool is a hammer, all problems look like your thumb.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1224888]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2019-10-23 21:50 GMT
Find Nodes?
    Voting Booth?