I recently did a ten-minute talk on Test-First of OO modules. This got me to thinking 'hey, I should put this on my blog' ... which got me to thinking 'hey, I should have a blog. If it were RSS enabled, Steve Hoek could use it to test his RSS Reader ...' :-)
So, here it is:
Let's say we're going to create a module called 'SomeObject'.
We knoew SomeObject will be a container, and it will take three optional paramaters on creation: The values of the entries at A, B, and C.
SomeObject will have two methods, 'Get' and 'Set'
So, we design the following tests:
1) Does SomeObject.pm compile?
2) Does SomeObject have new and get methods?
3) If I new, does it create a SomeObject object?
4,5,6) With the Object I created above, does it have the correct values for A, B, C?
7) Is the entry for D "Undefined?"
The tests are below:
#---------BEGIN CODE---------#
#use lib wherever SomeObject is. ('./')?
use Test::More;
BEGIN { plan tests => 7 };
use_ok('SomeObject');
can_ok('SomeObject', qw(new get) );
my $t = SomeObject->new(1,2,3);
isa_ok($t, 'SomeObject');
my $a = $t->get('A');
ok($a, 1, "Get 1st Parameter");
my $b = $t->get('B');
ok($b, 2, "Get 2nd Parameter");
my $c = $t->get('C');
ok($c, 3, "Get 3rd Parameter");
my $d = $t->get('D');
my $blnOk = 0;
if (!defined($d)) { $blnOk=1;}
ok($blnOk==1, "Making sure no extra variables are created");
# --- If we really wanted to be slick, I'd
# iterate from D to ZZZ or so, but I don't
# The for would have a bln we'd check, so we'd
# only have one variable, not 26*26*26.
#
#---------END CODE---------#
When you run the test file intially, only the use should pass, because you haven't even _coded_ the other methods.
Then, you code and test. Eventually, the test results look like this:
1..7
ok 1 - use PH::SomeObject;
ok 2 - PH::SomeObject->can(...)
ok 3 - The object isa PH::SomeObject
ok 4 - Get 1st Parameter
ok 5 - Get 2nd Parameter
ok 6 - Get 3rd Parameter
ok 7 - Making sure no extra variables are created
Pretty nifty eh?
Not really, but it's a good start.
That might be better written as:my $d = $t->get('D');
my $blnOk = 0;
if (!defined($d)) { $blnOk=1;}
ok($blnOk==1, "Making sure no extra variables are created");
my $d = $t->get('D');
ok(!defined($d), "Making sure no extra variables are created");
Re:Nit pick
Dom2 on 2003-08-05T16:05:53
It'd be written even better as:my $d = $t->get('D');
is( $d, 'expected_value', "get(D)");Use of is(), like() and isa_ok() is a very good thing where possible.
-Dom
ok($a==1, "Testing 1st Parameter");
is better written as
is( $a, 1, "Testing 1st Parameter");
for better diagnostics on failure. Any time you're writing
you probably wantok( $a == 1 )
unless your name is Nick Clark, in which case you reall, really meant '==' so itsis( $a, 1 );
cmp_ok($a, '==', 1 )
or Damian Conway, in which case there's probably a really good reason you used ok() instead of is().
Even better would be:
is( $a, 1, 'getting A' );
Mentioning that you're "testing" something in a test name is redundant and redundant, strike that out. Then there's the matter of properly describing what you're testing. You're not testing the first parameter, there's no order that I can see here, you're testing that you can get A.
Finally, assuming you don't need $a, which you don't...
is( $t->get('A'), 1, 'getting A');
why clutter up your code with unnecessary temp variables?
The last test, as mentioned before, is better written as:
ok( !defined $t->get('D'), 'no extra params created' )
to remove all that life support around it. But what if $t->get('D') did return something? How would we know what it was? Same way we do with everything else, use is().
is( $t->get('D'), undef, 'no extra params created' )