glasswalk3r has asked for the wisdom of the Perl Monks concerning the following question:

Greetings,

I'm writing some new tests for a project of mine (Siebel::Srvrmgr, available at CPAN) and during this activity I got stucked about using inheritance with Test::Class and the SUPER method.

Please consider that I had a superclass class Test::Action and subclasses of it. The superclass have methods that have to be invoked by the subclasses. Here is the code of it:

package Test::Action; use Test::Most; use Siebel::Srvrmgr::ListParser; use Test::Moose 'has_attribute_ok'; use base 'Test::Class'; sub class { 'Siebel::Srvrmgr::Daemon::Action' } sub get_my_data { return [qw(foo bar something)]; } sub startup : Tests(startup => 2) { my $test = shift; use_ok $test->class(); # keeps the subclass of Siebel::Srvrmgr::Daemon as an attribute ok( $test->{action} = $test->class()->new( { parser => Siebel::Srvrmgr::ListParser->new(), params => ['foobar'] } ), 'the constructor should succeed' ); } sub class_attributes : Tests(2) { my $test = shift; foreach my $attrib (qw(parser params)) { has_attribute_ok( $test->{action}, $attrib ); } } sub class_methods : Tests(6) { my $test = shift; my $parser_class = 'Siebel::Srvrmgr::ListParser'; isa_ok( $test->{action}->get_parser(), $parser_class, "get_parser returns" ); can_ok( $test->{action}, qw(new get_params get_parser get_params d +o) ); ok( $test->{action}->do( $test->get_my_data() ), 'do method works with an array reference' ); is( $test->{action}->do( $test->get_my_data() ), 1, 'do method returns 1 if output is used' ); dies_ok( sub { $test->{action}->do('simple string') }, 'do method raises an exception with wrong type of parameter' ) +; ok( $test->{action}->get_params(), 'get_params works' ); } 1;

In some tests subclasses, I had the need to invoke $test->SUPER::startup() or the tests just failed due errors during initialization. In other test subclass, calling SUPER or not does not change the test results (all pass).

In all subclasses code, I use something like this:

sub startup : Tests(startup => +1) { my $test = shift; $test->SUPER::startup(); ok( $test->{action} = $test->class()->new( { parser => Siebel::Srvrmgr::ListParser->new() } ), 'the constructor should succeed' ); }

Each subclass also overrides the parent class class() method, to return the correct class name to test.

What changes from the parent class to the child class is that the attribute "action" is defined by the parent, but later replaced by the subclass with another instance of another object.

One example of failure can be checked from the ActionLoadPreferences.t test.

C:\Temp\perl\Siebel-Srvrmgr>prove -I C:\Temp\perl\Siebel-Srvrmgr\t t\A +ctionLoadPreferences.t -v t\ActionLoadPreferences.t .. 1..22 ok 1 - use Siebel::Srvrmgr::Daemon::Action; ok 2 - the constructor should succeed# # Test::Action->class_attributes # ok 3 - The object does has an attribute named parser# Test::Action->cl +ass_methods ok 4 - The object does has an attribute named params ok 5 - get_parser returns isa Siebel::Srvrmgr::ListParser ok 6 - Siebel::Srvrmgr::Daemon::Action->can(...) ok 7 - do method works with an array reference # Failed test 'startup died (Can't locate object method "new" via pa +ckage "Siebel::Srvrmgr::Daemon::Action::LoadPreferences" (perhaps you + forgot to load "Siebel::Srvrmgr::Daemon::Action::Loa dPreferences"?) at t/Test/Action/LoadPreferences.pm line 13.)' ok 8 - do method returns 1 if output is used # at t\ActionLoadPreferences.t line 4. ok 9 - do method raises an exception with wrong type of parameter# ( +in Test::Action::LoadPreferences->startup) # Looks like you planned 22 tests but ran 13. ok 10 - get_params works# Looks like you failed 1 test of 13 run. not ok 11 - startup died (Can't locate object method "new" via package + "Siebel::Srvrmgr::Daemon::Action::LoadPreferences" (perhaps you forg +ot to load "Siebel::Srvrmgr::Daemon::Action::LoadPref erences"?) at t/Test/Action/LoadPreferences.pm line 13.) ok 12 # skip startup died ok 13 # skip startup died Dubious, test returned 1 (wstat 256, 0x100) Failed 10/22 subtests (less 2 skipped subtests: 10 okay) Test Summary Report ------------------- t\ActionLoadPreferences.t (Wstat: 256 Tests: 13 Failed: 1) Failed test: 11 Non-zero exit status: 1 Parse errors: Bad plan. You planned 22 tests but ran 13. Files=1, Tests=13, 1 wallclock secs ( 0.05 usr + 0.05 sys = 0.09 CP +U) Result: FAIL

I consider this kind of error at least "strange", since the parent class does not load or do anything to use Siebel::Srvrmgr::Daemon::Action::LoadPreferences, but the test subclass does have a class() method that returns Siebel::Srvrmgr::Daemon::Action::LoadPreferences class name.

I intended to use SUPER because the parent class execute some tests that I would like to execute in the subclasses as well, but I'm in doubt if I'm using it in the correct way.

Alceu Rodrigues de Freitas Junior
---------------------------------
"You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill