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

I'm trying to convert some existing home grown test scripts for an API to Test::Unit style tests. The way things were originally set up it makes sense in the new Test::Unit::TestCase's to do most of the set up once only and then have that fixture apply without modification to each test.

It seems that making use of Test::Unit::Setup would allow me to do that; call a single fixture set_up() once, before running the first test, then run all the tests and have a single tear_down at the end.

However, the documentation that comes with Test::Unit::Setup is sparse and contains not a single example of use. I can't make heads or tails of it.

Might there be another perl monk out that there that can give me a pointer (possible a baby example even) of how to incorporate a Test::Unit::Setup into a Test::Unit::TestCase?

advthanksance,

DrWhy

update: Just a couple of typos fixed

Replies are listed 'Best First'.
Re: How do I use Test::Unit::Setup?
by mvc (Scribe) on Jul 13, 2004 at 12:15 UTC
    ...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.

      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.

      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...