Why I hate writing tests.

ethan on 2003-09-21T09:14:01

They are by nature repetitive and tiring.

I'm done with all the XS and Perl code of String::Ruby and now need to test around 60 functions. Each test more or less has to be performed twice: for the functional interface and the autoboxed one. I decided to write one test-file for each function (resulting in around 60 .t files). I like each test-unit to be rather small, otherwise I quickly loose the orientation later.

The usual scheme is: input-string ==> apply function ==> output-string. For this module in particular, I need to always test special edge-cases. Those are: strings that contain 8-bit characters (should be left untouched for the moment) and strings containing the \0 character. Finally, one test tormenting the memory by feeding large strings.

It quickly dawned on me that

is(Capitalize("hello"), "Hello");
is not an option here. So I eventually put the needed test-data in an array over which I can repeatedly iterate. Now a test-file looks pleasantly terse and tidy:
use constant TESTS => 31; use Test::More tests => TESTS; use Storable qw(dclone);

BEGIN { use_ok("String::Ruby", functions => qw(capitalize capitalizeI)) }

my @tests = ( { str => "hello", res => "Hello", com => '' }, { str => "HELLO", res => "Hello", com => '' }, { str => "123ABC", res => "123abc", com => '' }, { str => "ääääää", res => 'ääääää', com => "8-bit characters" }, { str => "a" x 1_000_000, res => "A" . "a" x 999_999, com => "large string" }, { str => "h\0Ello", res => "H\0ello", com => "embedded \\0 character" }, );

for (@tests) { is(Capitalize($_->{str}), $_->{res}, $_->{com}); } for (my @cpy = @{ dclone(\@tests) }) { is(CapitalizeI($_->{str}), $_->{res}, $_->{com}); is($_->{str}, $_->{res}); } SKIP: { skip "autobox not available", 12 if (! &String::Ruby::HAVE_AUTOBOX); use String::Ruby qw(no_croak);

my @cpy = @{ dclone(\@tests) }; for (0 .. $#cpy) { is($cpy[$_]->{str}->capitalize, $cpy[$_]->{res}, $cpy[$_]->{com}); is($cpy[$_]->{str}, $tests[$_]->{str}); } }
I scanned the oodle of Test:: modules on the CPAN whether one already offers such an infrastructure. Ideally, the above @tests array should be a simple object so that I can access the fields by method and not by hash-subscript (because I am lazy). Also, I wonder whether I can sensibly optimize away all those for-loops. They could become methods-to-be-overriden in my fictious Test-class which @tests would be blessed into. Resulting only in one call to $tests->run.

And we already have so many test-modules all trying to be ultra-smart so that we clearly need yet another one.