root/branches/release-39/t/lib/Test/Class/Load.pm @ 2488

Revision 2488, 6.4 kB (checked in by mpaschal, 18 months ago)

Convert DDL tests to Test::Class in anticipation of failing tests
BugzID: 79949

Line 
1use strict;
2use warnings;
3
4package Test::Class::Load;
5
6use Test::Class;
7use File::Find;
8use File::Spec;
9
10our $VERSION = '0.03';
11
12# Override to get your own filter
13sub is_test_class {
14    my ( $class, $file, $dir ) = @_;
15    # By default, we only care about .pm files
16    if ($file =~ /\.pm$/) {
17        return 1;
18    }
19    return;
20}
21
22my %Added_to_INC;
23sub _load {
24    my ( $class, $file, $dir ) = @_;
25    $file =~ s{\.pm$}{};             # remove .pm extension
26    $file =~ s{\\}{/}g;              # to make win32 happy
27    $dir  =~ s{\\}{/}g;              # to make win32 happy
28    $file =~ s/^$dir//;
29    my $_package = join '::' => grep $_ => File::Spec->splitdir( $file );
30
31    # untaint that puppy!
32    my ( $package ) = $_package =~ /^([[:word:]]+(?:::[[:word:]]+)*)$/;
33
34    unshift @INC => $dir unless $Added_to_INC{ $dir }++;
35    eval "require $package"; ## no critic
36    die $@ if $@;
37}
38
39sub import {
40    my ( $class, @directories ) = @_;
41    my @test_classes;
42
43    foreach my $dir ( @directories ) {
44        $dir = File::Spec->catdir( split '/', $dir );
45        find(
46            {   no_chdir => 1,
47                wanted   => sub {
48                    my @args = ($File::Find::name, $dir);
49                    if ($class->is_test_class(@args)) {
50                        $class->_load(@args);
51                    }
52                },
53            },
54            $dir
55        );
56    }
57}
58
591;
60
61__END__
62
63=head1 NAME
64
65Test::Class::Load - Load C<Test::Class> classes automatically.
66
67=head1 VERSION
68
69Version 0.02
70
71=head1 SYNOPSIS
72
73 use Test::Class::Load qw(t/tests t/lib);
74 Test::Class->runtests;
75
76=head1 EXPORT
77
78None.
79
80=head1 DESCRIPTION
81
82C<Test::Class> typically uses a helper script to load the test classes.  It often looks something like this:
83
84 #!/usr/bin/perl -T
85
86 use strict;
87 use warnings;
88
89 use lib 't/tests';
90
91 use MyTest::Foo;
92 use MyTest::Foo::Bar;
93 use MyTest::Foo::Baz;
94
95 Test::Class->runtests;
96
97This causes a problem, though.  When you're writing a test class, it's easy to forget to add it to the helper script.  Then you run your huge test suite and see that all tests pass, even though you don't notice that it didn't run your new test class.  Or you delete a test class and you forget to remove it from the helper script.
98
99C<Test::Class::Load> automatically finds and loads your test classes for you. There is no longer a need to list them individually.
100
101=head1 BASIC USAGE
102
103Using C<Test::Load::Load> is as simple as this:
104
105 #!/usr/bin/perl -T
106
107 use strict;
108 use warnings;
109
110 use Test::Class::Load 't/tests';
111
112 Test::Class->runtests;
113 
114That will search through all files in the C<t/tests> directory and automatically load anything which ends in C<.pm>. You should only put test classes in those directories.
115
116If you have test classes in more than one directory, that's OK. Just list all of them in the import list.
117
118 use Test::Class::Load qw<
119   t/customer
120   t/order
121   t/inventory
122 >;
123 Test::Class->runtests;
124
125=head1 ADVANCED USAGE
126
127Here's some examples of advanced usage of C<Test::Class::Load>.
128
129=head2 FILTER LOADED CLASSES
130
131You can redefine the filtering criteria, that is, decide what classes are picked
132up and what others are not. You do this simply by subclassing
133C<Test::Class::Load> overriding the C<is_test_class()> method. You might want to
134do this to only load modules which inherit from C<Test::Class>, or anything else
135for that matter.
136
137=over 4
138
139=item B<is_test_class>
140
141  $is_test_class = $class->is_test_class( $file, $directory )
142 
143Returns true if C<$file> in C<$directory> should be considered a test class and be loaded by L<Test::Class::Load>. The default filter simply returns true if C<$file> ends with C<.pm>
144
145=back
146
147For example:
148
149  use strict;
150  use warnings;
151
152  package My::Loader;
153  use base qw( Test::Class::Load );
154
155  # Overriding this selects what test classes
156  # are considered by T::C::Load
157  sub is_test_class {
158      my ( $class, $file, $dir ) = @_;
159
160      # return unless it's a .pm (the default)
161      return unless $class->SUPER:is_test_class( $file, $dir );
162   
163      # and only allow .pm files with "Good" in their filename
164      return $file =~ m{Good};
165  }
166
167  1;
168
169=head2 CUSTOMIZING TEST RUNS
170
171One problem with this style of testing is that you run I<all> of the tests every time you need to test something.  If you want to run only one test class, it's problematic.  The easy way to do this is to change your helper script by deleting the C<runtests> call:
172 
173 #!/usr/bin/perl -T
174
175 use strict;
176 use warnings;
177
178 use Test::Class::Load 't/tests';
179
180Then, just make sure that all of your test classes inherit from your own base class which runs the tests for you.  It might looks something like this:
181
182 package My::Test::Class;
183 
184 use strict;
185 use warnings;
186
187 use base 'Test::Class';
188
189 INIT { Test::Class->runtests } # here's the magic!
190
191 1;
192
193Then you can run an individual test class by using the C<prove> utility, tell it the directory of the test classes and the name of the test package you wish to run:
194
195 prove -lv -It/tests Some::Test::Class
196
197You can even automate this by binding it to a key in C<vim>:
198   
199 noremap ,t  :!prove -lv -It/tests %<CR>
200
201Then you can just type C<,t> ('comma', 'tee') and it will run the tests for your test class or the tests for your test script (if you're using a traditional C<Test::More> style script).
202
203Of course, you can still run your helper script with C<prove>, C<make test> or C<./Build test> to run all of your test classes.
204
205If you do that, you'll have to make sure that the C<-I> switches point to your test class directories.
206
207=head1 SECURITY
208
209C<Test::Class::Load> is taint safe.  Because we're reading the class names from the directory structure, they're marked as tainted when running under taint mode.  We use the following ultra-paranoid bit of code to untaint them. Please file a bug report if this is too restrictive.
210
211 my ($package) = $_package =~ /^([[:word:]]+(?:::[[:word:]]+)*)$/;
212
213=head1 AUTHOR
214
215Curtis "Ovid" Poe, C<< <ovid@cpan.org> >>
216
217=head1 BUGS
218
219Please report any bugs or feature requests to C<bug-test-class-load@rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Class-Load>. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
220
221=head1 ACKNOWLEDGMENTS
222
223Thanks to David Wheeler for the idea and Adrian Howard for C<Test::Class>.
224
225=head1 COPYRIGHT & LICENSE
226
227Copyright 2006 Curtis "Ovid" Poe, all rights reserved.
228
229This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Note: See TracBrowser for help on using the browser.