in reply to TDD: a test drive and a confession
Ah, yes, one of my favorite subjects :)
The single greatest benefit that I have gained from tests is that I am a better programmer. It's not just that I can run my tests and know that my code works; by writing my tests first, I am forced to look at things from the standpoint of interfaces and who will be using my code. I need things to be simple and intuitive. As a result, my code is more likely to be simple and intuitive. Quite frequently, after a heavy refactoring of legacy code, I find myself with a module that has a bunch of one line methods that rarely take more than one argument (other than $self). That makes me feel good.
And I always find strange bugs that I never thought about, but I also find myself writing fewer bugs since I am focusing on the simplest thing that can get the tests to pass.
The non-deterministic factor is what worries me. That's actually quite a debate at my current job. Currently, we create test data, put it in a database and then nod when we get the test data back out. I think that's a problem because we're testing our expections or what the data should look like rather than testing what the data actually is. The rebuttal is "we can't test it if we don't know what it returns". In other words, they're afraid of non-deterministic tests.
There are plenty of ways to get around this. We can make raw SQL queries against a copy of the live data to verify that the code returns the correct data. We can use regular expressions to verify that the form of the data that we return is correct, or subroutines that return true or false depending upon whether or not the data is in the correct domain (e.g, day of week is 1 to 7 instead of an integer).
Finally, you can use Test::MockObject to override the difficult interfaces. If you find this is too much overhead, you can also override interfaces directly in your code. Here's one handy method. The subroutine you test calls fetchrow_arrayref internally:
my $results; my $test_data = [qw{foo bar baz}]; { no strict 'refs'; local $^W; # suppres redefined warnings my $arrayref_called = 0; local *{'DBI::fetchrow_arrayref'} = sub {$arraref_called++; $test_ +data }; $results = some_func($some_arg); is($arrayref_called, 1, '... and fetchrow_arrayref should be calle +d only once'); } ok($results, '... and some_func succeeded'); is_deeply($results, $test_data, '... and it should return the correct +data');
Finally, for troublesome built-ins that can be overridden, try ex::override.
my @rand = qw/ 0.78195951257749 0.625570958105044 0.884315045123127 0.137177303290578 0.0650888668725038 /; use ex::override rand => sub {unshift @rand => pop @rand; $rand[0]}; print rand, $/ for 1 .. 5;
Now you have deterministic "random" numbers :)
Cheers,
Ovid
New address of my CGI Course.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Re: TDD: a test drive and a confession
by gwadej (Chaplain) on Sep 18, 2003 at 03:36 UTC | |
|
Re: Re: TDD: a test drive and a confession
by demerphq (Chancellor) on Sep 18, 2003 at 22:42 UTC |