1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
package Test::FITesque::Test;
use strict;
use warnings;
use Module::Load;
use Test::Builder;
our $TEST_BUILDER;
our $METHOD_DETAIL_VERBOSE;
=head1 NAME
Test::FITesque::Test - A FITesque test
=head1 SYNOPSIS
my $test = Test::FITesque::Test->new();
# add test rows
$test->add( ... );
$test->add( ... );
# return number of TAP tests
$test->test_count();
$test->run_tests();
=head1 DESCRIPTION
=head1 METHODS
=head2 new
my $test = Test::FITesque::Test->new();
This is a simple constructor. It takes a hashref of options:
=over
=item data
This is an arrayref of arrayrefs for the FITesque run.
=back
Please note that the first test row that is added must be the FITesque fixture
class name, followed by the arguments to be passed to its constructor.
=cut
sub new {
my ($class, $args) = @_;
$args ||= {};
my $self = bless $args, $class;
return $self;
}
=head2 add
$test->add(qw(Foo::Fixture some constructor args));
$test->add('click button', 'search');
This method allows you to add FITesque test rows individually. As with the data
option in the constructor, the first row added must be the Fixture class name
and its constructor arguments.
=cut
sub add {
my ($self, @args) = @_;
$self->{data} ||= [];
push @{ $self->{data} }, [@args];
}
=head2 test_count
my $count = $test->test_count();
This method returns the number of TAP tests expected to be run during the
test run.
=cut
sub test_count {
my ($self) = @_;
my $data = $self->{data} || [];
if(@$data){
my ($fixture_class) = $self->_load_fixture_class();
my $count = 0;
for my $test_row ( @$data[ 1..( scalar(@$data) -1) ]){
my $method_string = $test_row->[0];
my $test_count = $fixture_class->method_test_count($method_string) || 0;
$count += $test_count;
}
return $count;
}
return 0;
}
=head2 run_tests
$test->run_tests();
This method will run the FITesque test based upon the data supplied.
=cut
sub run_tests {
my ($self) = @_;
my $data = $self->{data} || [];
if(@$data){
my ($fixture_class, @fixture_args) = $self->_load_fixture_class();
my $fixture_object;
if(!defined $self->{__test_has_run__}){
@fixture_args = $fixture_class->parse_arguments(@fixture_args);
$fixture_object = $fixture_class->new(@fixture_args);
$self->{__test_has_run__} = 1;
} else {
die q{Attempted to run test more than once};
}
# Deal with being called directly or as part of a suite
my ($pkg) = caller();
if(!$pkg->isa('Test::FITesque::Suite')){
my $Builder = $TEST_BUILDER ? $TEST_BUILDER : Test::Builder->new();
$Builder->exported_to(__PACKAGE__);
if ( $Builder->isa('Test::FakeBuilder') || !$Builder->has_plan) {
if( my $count = $self->test_count() ){
$Builder->expected_tests($count);
} else {
$Builder->no_plan();
}
}
}
# early bail out in case of unavailable methods
# - We do this as a seperate step as the method called could take a long
# time, which would mean that you'd only fail halfway through a long
# test run.
for my $test_row (@$data[ 1..(scalar(@$data) -1) ]){
my $method_string = $test_row->[0];
if( !$fixture_object->parse_method_string($method_string) ){
die qq{Unable to run tests, no method available for action "$method_string"}
}
}
for my $test_row ( @$data[ 1..( scalar(@$data) -1) ]){
my $Builder = $TEST_BUILDER ? $TEST_BUILDER : Test::Builder->new();
my ($method_string, @args) = @$test_row;
my $method = $fixture_object->parse_method_string($method_string);
die "No method exists for '$method_string'" if !defined $method;
my $test_count = $fixture_object->method_test_count($method_string) || 0;
my $msg = "running '$method_string' in class '$fixture_class' ($test_count tests)";
$Builder->diag( $msg ) if $METHOD_DETAIL_VERBOSE;
@args = $fixture_object->parse_arguments(@args);
$fixture_object->$method(@args);
}
}else{
die "Attempted to run empty test";
}
}
sub _load_fixture_class {
my ($self) = @_;
my $data = $self->{data};
my ($class,@args) = @{ $data->[0] };
eval {
load $class;
};
die qq{Could not load '$class' fixture: $@} if $@;
die qq{Fixture class '$class' is not a FITesque fixture}
if !$class->isa(q{Test::FITesque::Fixture});
return ($class, @args);
}
=head1 AUTHOR
Scott McWhirter, C<< <konobi@cpan.org> >>
=head1 COPYRIGHT & LICENSE
Copyright 2007 Scott McWhirter, all rights reserved.
This program is released under the following license: BSD. Please see the
LICENSE file included in this distribution for details.
=cut
1;
|