Writing Test Cases

     

Consider a Queue object that stores items to access in first-in, first-out order. Queue allows you to enqueue and dequeue items, returning them in insertion order. You can query a Queue for how many items it contains. Sure, it's simple enough to do this with Perl's basic data structures, but the complexity of Queue could grow quickly as its uses supersede what a normal array provides.

This lab demonstrates how to test Queue by creating a module that subclasses Test::Class .

How do I do that?

Create a directory Queue/ and save the following as Queue/Test.pm :

 package Queue::Test;          use base 'Test::Class';          use Queue;     use Test::More;          sub size : Test(4)     {         my $q1 = Queue->new(  );         isa_ok( $q1, 'Queue' );         is( $q1->size(  ), 0, 'an empty queue' );              my $q2 = Queue->new(qw( howdy bonjour ));         isa_ok( $q2, 'Queue' );         is( $q2->size(  ), 2, 'a queue with some elements' );     }          sub enqueue : Test(2)     {         my $queue = Queue->new(  );         isa_ok( $queue, 'Queue' );              $queue->enqueue($_) for qw( howdy bonjour );         is( $queue->size(  ), 2, 'queue is now larger' );     }          sub dequeue : Test(6)     {         my $queue = Queue->new(  );         isa_ok( $queue, 'Queue' );              is( $queue->dequeue, undef, 'empty queue' );              $queue->enqueue($_) for qw( howdy bonjour );         is( $queue->size(  ),    2,         'queue is now larger'  );         is( $queue->dequeue(  ), 'howdy',   'first item'           );         is( $queue->dequeue(  ), 'bonjour', 'second item'          );         is( $queue->size(  ),    0,         'queue is now smaller' );     }          1; 

The Queue class is fairly simple as far as Perl objects go. Save it as Queue.pm :

 package Queue;          use strict;     use warnings;          sub new     {         my ($class, @items) = @_;         bless \@items, $class;     }          sub size     {         my ($self) = @_;         return scalar @$self;     }          sub enqueue     {         my ( $self, $item ) = @_;         push @$self, $item;     }          sub dequeue     {         my ( $self ) = @_;         return shift @$self;     }          1; 

Save the test file as queue.t :

 #!perl          use Queue::Test;          Test::Class->runtests(  ); 

Finally, run queue.t with prove :

 $  prove queue.t  queue....#     # Queue::Test->test_dequeue     1..12     ok 1 - The object isa Queue     ok 2 - empty queue     ok 3 - queue is now larger     ok 4 - first item     ok 5 - second item     ok 6 - queue is now smaller     #     # Queue::Test->test_enqueue     ok 7 - The object isa Queue     ok 8 - queue is now larger     #     # Queue::Test->test_size     ok 9 - The object isa Queue     ok 10 - an empty queue     ok 11 - The object isa Queue     ok 12 - a queue with some elements     ok     All tests successful.     Files=1, Tests=12,  1 wallclock secs ( 0.19 cusr +  0.00 csys =  0.19 CPU) 

What just happened ?

The test file you saved as queue.t has a very simple job: to run all of the test methods defined in the Queue::Test class. Test::Class is smart ”it keeps track of any module that subclasses it. All you need to do is use your test modules and call runtests( ) on Test::Class itself.

You can use any Test::Builder testing module with Test::Class , such as Test::Exception or Test::Deep . Most test classes use at least Test::More 's basic testing functions.

To designate a method as containing tests, add a Test( n ) attribute that declares how many tests the method contains. Test::Class automatically adds them all up and declares a plan for you, so you don't need to scan through giant test files to count all of your is( ) and ok( ) functions. If you don't know how many tests a method will contain, use the Test(no_plan) attribute.


Note: Subroutine attributes are the things after the subroutine name and before the opening brace . See perldoc attributes to learn more .

If your test methods die or return before the end of the test method, Test::Class will produce fake skipped tests enough times to complete the test count declared in the Test attribute. Dying in a test method produces a test failure, and returning skips the remaining tests in the method. However, if you return when you use Test(no_plan) , you won't have any idea if there are tests after the return statement that should have run!

When you run your tests with verbose mode (either by using the -v option with prove or by setting the TEST_VERBOSE environment variable), Test::Class outputs the name of the test method before it runs any tests for that method. This is a nice way to see where certain tests come from while debugging. Also, if you don't specify test descriptions in your test functions, Test::Class uses the name of the current test method as the test description.

What about...

Q:

Should I use Test in all of my module names ?

A:

The standard naming convention for unit testing is to suffix the class name you're testing with Test . The example code in this lab used this convention for clarity, but naming your classes like this isn't completely necessary.

An alternative naming scheme for the test classes is to name them in the manner of other object-oriented modules. For example, the Queue::Test::Word class inherits from Queue::Test . Opinions vary on which is the best approach, so choose the style that fits your team and project.

Q:

What if I distribute this module? Will my test classes install along with my other modules?

A:

If your Makefile.PL or Build.PL doesn't explicitly state what modules it's going to install, yes. By default, ExtUtils::MakeMaker and Module::Build look in the lib/ directory of the distribution for any modules to install. If you don't want to install your test classes, see "Using Temporary Databases" in Chapter 6, which describes using a separate build_lib/ directory for the testing- related modules.

Of course, if your project is a framework you expect people to subclass, installing the test modules will allow them to inherit tests as well.

Q:

Can I control the order in which the tests run?

A:

Test::Class runs all groups of tests in alphabetical order. First, all startup methods run in alphabetical order. Next, the test methods run in alphabetical order. Finally, the shutdown methods run in alphabetical order. For every test method, its setup methods run in alphabetical order. Then the test method itself runs. Finally, its teardown methods run in alphabetical order. ("Creating Test Fixtures," next , explains setup and teardown methods and fixtures.)



Perl Testing. A Developer's Notebook
Perl Testing: A Developers Notebook
ISBN: 0596100922
EAN: 2147483647
Year: 2003
Pages: 107

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net