in reply to How do I use Test::Unit::Setup?

...use of Test::Unit::Setup would allow me to do that; call a single fixture set_up() once...

Yep. Except you don't call set_up(), the framework does. Once for each test method run. It is a template method, and if you have an inheritance hierarchy of test classes, you may need to call SUPER::set_up() when implementing this method.

The simplest example I could find is this abstract base class, which is inherited by all model tests in Rui (some framework). It helps with creating a fresh Implementation Under Test before running each test method:

package Rui::Model::tests::ModelTestCase;

use base 'Test::Unit::TestCase';

sub set_up    { shift->makeModel      }
sub tear_down { delete shift->{model} }

# protected utility factory method for subclasses
sub makeModel {
   my ($self, %params) = @_;
   my $modelClass = $self->getModelClass;
   return $self->{model} = $modelClass->new(%params);
}

# template method for subclasses
sub getModelClass { die "abstract method called" }

As you see this is not a test class, but a useful base class. Instead of doing this at the start of each test method that creates models:

sub test_foo {
   my $self = shift;
   my $model = SomeClass->new;
   # arrange, apply, and assert here, all on our IUT: $model
}

You can do this instead:


use base 'Rui::Model::tests::ModelTestCase';

sub getModelClass { 'SomeClass' }

sub test_foo {
   my $self = shift;
   # $self->{model} already has a fresh IUT in it
   # arrange, apply, and assert here, all on our IUT: $model
}

Make sure you look at Test::Class, as it supports most of the features in Test::Unit, but plays better with Perl testing modules, and has a nicer API. It is also a living project compared with Test::Unit. I switched, and am mostly happy.

Of course with the Aspect module, such things become even easier, but this code was just an example showing where set_up()/tear_down() are useful: in creating a fresh fixture. Look in XUL-Node for examples of using Test::Class together with aspects.

Replies are listed 'Best First'.
Re^2: How do I use Test::Unit::Setup?
by adrianh (Chancellor) on Jul 13, 2004 at 13:34 UTC
    Make sure you look at Test::Class, as it supports most of the features in Test::Unit, but plays better with Perl testing modules, and has a nicer API.

    I'm positively blushing ;-)

    I switched, and am mostly happy.

    What more do you want (he asks curiously) ? I can almost certainly be tempted to add it to the todo list.

Re^2: How do I use Test::Unit::Setup?
by DrWhy (Chaplain) on Jul 13, 2004 at 15:57 UTC
    No, see, I want to establish a set_up/tear_down that are exectuted not once for each test, but a set_up that is run once before the first test is run, and a teat_down that is run once after the last test is run. If my reading of Test::Unit::Setup are correct this allows you to do this. However, I'm not sure how the Test::Unit::Decorators (Test::Unit::Setup isa Decorator) in relation to Test::Unit::TestCase (or is it supposed to be used with a TestSuite?)

    Still needing help with this...

    P.S. Our group is already pretty heavily invested in Test::Unit, but I can ask the other guys what they think of Test::Class...

      No, see, I want to establish a set_up/tear_down that are exectuted not once for each test, but a set_up that is run once before the first test is run, and a teat_down that is run once after the last test is run.

      Test::Unit::Setup is a decorator for suites, not test cases, so you'll need to do something like this:

      package My::TestCase; use base qw(Test::Unit::TestCase); use Test::Unit::TestSuite; sub test_the_first { my $self = shift; $self->assert( 1, 'first' ); } sub test_the_second { my $self = shift; $self->assert( 1, 'second' ); } sub suite { return MySuiteSetup->new( Test::Unit::TestSuite->new( __PACKAGE__ ) ); } package MySuiteSetup; use base qw( Test::Unit::Setup ); sub set_up { warn "before all tests\n"; } sub tear_down { warn "after all tests\n"; }
      Our group is already pretty heavily invested in Test::Unit, but I can ask the other guys what they think of Test::Class

      Just as a point of comparison, this would be how you would do it in Test::Class.

      package My::Test; use base qw( Test::Class ); use Test::More; sub before :Test( startup ) { warn "before all tests\n"; }; sub first :Test { pass }; sub second :Test { pass }; sub after :Test( shutdown ) { warn "after all tests\n"; };

      You might also be interested in PerlUnit@yahoogroups.com, a mailing list dedicated to Test::Unit. Traffic has been sparse though...

        Test::Unit::Setup is a decorator for suites, not test cases, so you'll need to do something like this:

        package My::TestCase; use base qw(Test::Unit::TestCase); use Test::Unit::TestSuite;
        Thanks adrianh! This is just the bit I needed to make it come together in my head.