Andrew F. Hampe > Wetware-Test > Wetware::Test

Download:
Wetware-Test-0.07.tar.gz

Dependencies

Annotate this POD

View/Report Bugs
Module Version: 0.07   Source  

NAME ^

Wetware::Test - Wetware Test::Class extensions

DESCRIPTION ^

This is a step towards stream lining the process of creating and maintaining Test::Class based Test Driven Development.

Ultimately I would like to have a tool that would create a Foo::TestSuite for all Foo Classes that are in the distribution.

This means setting the 01_test_class.t to look into blib/lib which will help the over all process. This way any Test::Class based TestSuite.pm module will also be installed, so that subclasses of FOO will be able to inherit from Foo::TestSuite.

Caveat: this now needs a fix in the Test::Compile approach to avoid the TestSuite.pm files.

This distribution also offers the illustration of one strategy for doing the 01_test_class.t - which runs all of the modules in t/lib. It should be noted that Wetware::Test::Utilities is a Functional Module, and so it inherits directly from Wetware::Test::Class - since there is no need for the sorts of set_up/tear_down etc that are useful for OO testing.

INTRO TO Modules ^

This distribution provides five modules:

I am putting these in the Wetware space, because I want to get the ideas out there, and I want to implement a Wetware::CLI that will have an appropriate Test::Class based testing.

It also means that I do not have to rumage around for those neat tricks.... Just put them into a distribution, and then call the appropriate module.

OVERVIEW ^

When a module is started with module_starter, it provides some nice basic starting t/ test files.

What it will not do is teach about the difference between unit and functional testing, and/or the utility of Test Driven Development.

This overview I hope will help with the simple pragmatics of setting up a Test::Class approach to development.

The simplest strategy is to have a file named TestSuite.pm that shadows every module being created. Thus if there is a My::Module:: in the lib/ then in t/lib/My/Module/TestSuite.pm will be the My::Module::TestSuite.

It could begin with as simple a starting module as:

 package My::Module::TestSuite;

 use strict;
 use warnings;
 use base q{Wetware::Test::Suite};

 use Test::More;
 use My::Module;

 #--------------------------------------------------

 sub class_under_test { return 'My::Module'; }

 #--------------------------------------------------

 sub test_new : Test(1) {
        my $self           = shift;
        my $object         = $self->object_under_test();
        my $expected_class = $self->class_under_test();

        Test::More::isa_ok( $object, $expected_class );
        return $self;
 }

This shows that the class_under_test method overrides the method in Wetware::Test::Suite. But the set_up(), tear_down and object_under_test() were just hapily inherited in.

Add the equally simple 01_test_class.t script:

     use strict;
     use warnings;
     use FindBin qw($Bin);
     use Wetware::Test::Class::Load "$Bin/../blib/lib";

into the t/ directory, and the process can begin.

{ remember to do the perl Build.PL, since one is adding files that were not taken account of when Build was created last. Also remember to update the Manifest... and eat regularly... }

If there is a subclass My::Module::SubClass which inherited from My::Module, then it's TestSuite would likewise inherit.

 package My::Module::SubClass::TestSuite;

 use strict;
 use warnings;
 use base q{My::Module::TestSuite};

 use Test::More;
 use My::Module::SubClass;

 #-------------------------------------------------------

 sub class_under_test { return 'My::Module::SubClass'; }

and it would inherit the first test - test_new() from My::Module::TestSuite. This is also an advantange that any test that is written for the base class will be inherited into all of the subclasses.

Since the 01_test_class.t will load and test all modules in t/lib, there is no need to update and maintain an additional test script.

As noted in the pod for Wetware::Test::Class, any individual TestSuite can be run, either with prove, or through the build

 ./Build test test_files=t/lib/My/Module/SubClass/TestSuite.pm

But the general speed up that comes using the Test::Class::Load means that the tests in general will run fast enough.

BACKGROUND ^

Once upon a time we were converting some legacy code, and starting the transition from the Test::More apporach where there is one test script in t/ for each module.

Since there were several modules in that distribution that were subclasses, using Test::Class was a great step forward. But there was still one test script for each module.

The big bottle neck in the process is compiling each test script.

The Test::Class::Load module provides the lifting needed to have a single script run all of the Test Suite Modules in t/lib. This requires that thers is a module that inherits from Test::Class and implements the INIT block, like:

 package OUR::Test::Class;

 use strict;
 use warnings;

 use Test::Class;
 use base 'Test::Class';
 our $VERSION = 0.01;

 INIT { Test::Class->runtests() }

Which all of the modules will inherit from. Then you can call them all with the 00_test_class.t script.

Then when we started a new project, I asked if we could have some sort of base TestSuite module, so that everyone inherited the same five basic methods. It would inherit from OUR::Test::Class, and thus all of it's sub classes would run contentedly.

Now all that one needs to do when creating complex distributions is to start with simple steps. There will need to be the 00_test_class.t test script in t/ and now one can create the Test::Class based modules in t/lib/Your/Space that will shadow the classes in lib/Your/Space.

CHANGE STOCK test files ^

There are two semi standard .t test scripts that need to be changed to work and play well with the TestSuite approach, since if one attempts to do the simple Test::Compile of any Module that inherits from a Test::Class based module with the INIT block, they will fail becaue 'it is too late for INIT' - this is also true of Pod Coverage.

So the fix is to call a sub.

Modify pod-coverage.t to use:

 all_non_testsuite_pod();

 #-------------------------------------------------------------

 sub all_non_testsuite_pod {

        my @modules = grep { $_ !~ m{::TestSuite$} } all_modules();
        plan tests => scalar @modules;
        foreach my $module ( @modules ) {
                pod_coverage_ok($module);
        }
        return;
 }

And it will filter out the modules *::TestSuite.

The compile_pm script is about the same, except that it runs with module file names:

 all_non_testsuite_modules();

 #----------------------------------------------------------------

 sub all_non_testsuite_modules {

        my @modules = grep { $_ !~ m{/TestSuite.pm$} } all_pm_files();
        plan tests => scalar @modules;
        foreach my $module ( @modules ) {
                pm_file_ok
                ($module);
        }
        return;
 }

Remember that you will need to add the 'use Test::More;' so that you have access to the plan.

TRADE OFF

I am working on Wetware::Test::CreateTestSuite that will help with creating the right types of t files.

So that it will be simpler to use both a Foo::TestSuite in the lib, rather than in t/lib, so that it can be inherited by those who wish to sub class....

But also so that there is not the loss of functionality of having pod_coverage.t and Test::Compile tests.

That module will deliver a create_testsuite tool to help the process of automating Test::Class based Test Driven Development.

BUT, this will require that users opt to do the right thing.

Some of this can be solved in code, but it will also require some rethinking about how the processes is done.

AUTHOR ^

"drieux", <"drieux [AT] at wetware.com">

SEE ALSO ^

Wetware::Test::CreateTestSuite

Wetware::Test::Class

Wetware::Test::Class::Load

Wetware::Test::Suite

Wetware::Test::Utilities

Wetware::Test::Mock

Test::Class

Test::Class::Load

Test::More

Test::Differences - great eq_or_diff_text() method!

Test::Exception - because some things NEED to throw exceptions.

module-starter - the way to start a new module

ACKNOWLEDGEMENTS ^

A special thanks to Jeffrey Ryan Thalhammer <thaljef@cpan.org> for helping me understand the Test::Class::Load approach.

And a BIG thanks to Matisse Enzer for his commitment to Test Based Design.

COPYRIGHT & LICENSE ^

Copyright 2009 "drieux", all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

syntax highlighting: