Test-Class-0.50/000700 000766 000024 00000000000 12534705543 013671 5ustar00etherstaff000000 000000 Test-Class-0.50/Changes000755 000766 000024 00000041764 12534705474 015220 0ustar00etherstaff000000 000000 Changes for Perl extension Test-Class 0.50 [2015-06-07] - add links to Ovid's tutorial series on Test::Class (Tim Vroom, PR#19) - add links to Test::Class::Most, Test::Class::Moose (Tim Vroom, PR#20) - list some distributions that use Test::Class in their test suite (Tim Vroom, PR#21) - update documentation about running individual tests (Matthew Horsfall, PR#22) - fix some tests to work with the new Test::Stream (Chad Granum, PR#27) - switch packaging to ExtUtils::MakeMaker 0.48 [2014-11-06] - replace a few bare evals with more modern alternatives 0.47 [2014-09-26] - fixes for Test::More 1.301001_* series (PR#17, PR#18, Chad Granum) 0.46 [2014-07-06] - fix new teardown tests for MSWin32 0.45 [2014-07-05] - bump minimum required version of Test::More (RT#96951) 0.44 [2014-07-04] - run teardown method even if test method dies, as in version 0.37 and earlier 0.43 [2014-06-25] - specify test prereqs as test_requires rather than build_requires 0.42 or the "how did I get stuck with co-maint?" release [2014-05-07] - properly handle thrown exceptions that stringify to the empty string before or after chomping (Karen Etheridge, PR#11) 0.41 or the "0.99 was a bad year" release [2013-11-30] - require a newer Test::Builder if 0.99 is installed RT#90699 0.40 or the "rjbs wants to install App::GitGot" release [2013-11-04] - Applied Zefram's fix for RT#89473, Test::Class fails on Test::Builder 0.99 0.39 or the "For the QA Hackathon 2013" release [2013-04-12] - Merged schwern's https://github.com/adrianh/test-class/pull/2 "Fix Test::Class for Test::Builder 1.5" - thank you Schwern! 0.38 or the "We need Test::Class to work on Windows" release [2012-11-19] - Many thanks to the ever excellent Ovid for actually making this happen. - die-in-setup.t will work on Windows (thanks to Alexandr Ciornii for the patch) - Fix docs to explain "no_plan" in start up" (thanks to skington for the patch) 0.37 - or the "amazingly late QA Hackathon 2011" release [2012-06-25] - Fixed RT#64470: minor documentation error in Test::Class::Load (thanks to Andrew Grangaard for patch) - Fixed RT#39266: Test::Class with Package::Alias - Fixed RT#56636: feature request: option to turn off auto-skipping uncompleted tests (thanks to Ken Fox for suggestion) with addition of fail_if_returned_early() (thanks to Dave Evans for patch) - Fixed RT#64268: dying in setup does not skip rest of test - Startup and shutdown methods are no longer run if a class will not run any test methods - Updated acknowledgements - Added missing filter tests to MANIFEST & distribution 0.36 - or the "Adrian should have released this earlier" release [2010-08-19] (Thanks to Mark Morgan for doing all the useful work on this one!) - New add_filter() method allows global filtering of test methods - Apply t/todo.t patch to fix RT#55324 (test bug, not Test::Class bug). This makes the test suite pass with Test::Simple 0.95_01 and greater. 0.35 - or the "Yay! Open Source For The Win!" release [2010-04-28] - Introducing Ovid & Mark Morgan in "Folk with commit bits who aren't afraid to use them!" - Add repository information to the META.yml (via Build.PL). - Add dates to all releases in Change file. This resolves RT#45581 - If extra tests are found in the test control methods, report the class name along with the method name. 0.34 - or the "Abandon ship!" release [2010-03-08] - Harmonised $VERSION to the same value (Adam Kennedy) - Devel::Symdump has a bug which is really a bug in core and won't be fixed. Dumped it and switched to MRO::Compat instead (tokuhirom) - Add "build_requires" (Alexandr Ciornii) 0.33 - or the "ZOMGIBROKECPAN" release [2009-09-21] - Make the test scripts adaptive to Test::More diagnostic changes in version 0.88 - Skip invalid package names in Test::Class::Load::_load so that we don't try to load classes in .svn/et-al paths - Removed #! script invocation line from the MethodInfo.pm module 0.32_1 - or the "Birmingham QA 2009" release [2008-03-28] - Removed pointless use of Test::Exception in t/bad-autoloads.t to stop bogus warnings that were confusing some folk - Added add_testinfo for Test::Class::Sugar (thanks Piers Cawley) 0.31 - or the "good god adrian is still alive" release [2008-09-14] - Downgraded IO::File dependancy to 1.09 (RT#38424 - thanks Mark Stosberg) 0.30 - or the "Oslo QA 2008 #2" release [2008-04-07] - Move up to depend on Test::Simple 0.78 to stomp on RT##33809 0.29 - or the "Oslo QA 2008" release [2008-04-06] - Fixed some broken edge cases where you didn't get a plan when you had tests in a shutdown method, and no tests in the rest of your class - Test::Class::Load can now be subclassed so you can add your own filters for what is considered a test class (patch from Cosimo Streppone) - Described minimum perl as '5.006001' rather than '5.6.1' so old perls understand what we're talking about. - Fixed typo in docs (thanks Tony Edwardson) 0.28 - or the "just for the debian folk" release [2008-01-15] - Downgraded some dependencies to avoid some bogus warnings on Debian (thanks Gunnar Wolf & Hynek) 0.27 - or the "Adrian cannot write in English" release [2007-12-29] - Fixed a couple of typos/grammar stupidities (thank Jim Brandt) 0.26 - or the "really working on windows this time (fingers crossed)" release [2007-12-10] - Tests that look at test_err from Test::Builder::Tester now use caller() to get the filename - just like Test::Builder. So hopefully everything should work on all platforms this time. - Updated the Test::* version dependencies to something vaguely modern - Fixed runtests_die.t, which still had platform-specific paths in 0.25 - or the "idiotic platform specific tests fixed" release [2007-12-07] - Fixed RT#31122 that was failing tests on Strawberry Perl (thanks to Chris Dolan) 0.24 - or the "hating perl's broken object model" release [2007-03-01] - Stopped throwing warnings when Contextual::Return was loaded due to the AUTOLOADING of isa() (thank's to agianni) - If you are filtering with TEST_METHOD your startup/shutdown methods still get executed (thanks Chris Dolan) 0.23 - or the "damn David and his smoke testing" release [2007-02-23] - Added explicit dependency on Test::Simple for those odd folk who have old Test::Simple releases running with a recent Test::Builder::Tester (thanks David Cantrell) 0.22 - or the "++ becomes a legal regex" release [2006-11-29] - Factored out some common code - Added test for Test::Class::Load not loading modules successfully - Tidied up all the T::C::L test libraries into t/test-libs - Added patch from Nicholas Clark to make T::C work with blead perl 0.21 - or the "we're all growed up" release [2006-11-01] - expected_tests() gives a sensible info when given undef as an argument - fixed bug when we repeatedly wrapped Test::Builder::ok with extra Test::Class functionality every time we run a test method - Test::Class::Load only adds directories to @INC once 0.20 - or the "you failed where?" release [2006-10-19] - Added an extra diagnostic line on test failures that list the method that failed and the class being tested. Makes locating test failures in test class hierarchies much simpler. - Added some tests for plan math for startup/shutdown methods (phew they worked!) 0.19 - or the "last RT bug crushed" release [2006-10-11] - You now get a sensible error message if you load Test::Class after the CHECK phase where the :Test attribute gets applied. - Added "A NOTE ON LOADING TEST CLASSES" section that describes the issue of the :Test attribute being applied at CHECK time 0.18 - or the "damn multiple inheritence" release [2006-10-06] - You now get a sensible error message if Test::Class's new() gets overridden badly via a subclass or multiple inheritance 0.17 - or the "wot I did on the train" release [2006-10-06] - Removed pointless uses of UNIVERSAL::isa - We rename "test name" to "test description" to confirm with current TAP nomenclature - Added some pointers to third party documentation - Added references to Test::Object, Test::Group and Test::Block - Actually added spelling.t to the distro (sigh) 0.16 - or the "sepling mist ook!" release [2006-10-04] - Added (optional) spelling tests for the POD in t/developer - Fixed a whole bunch of spelling mistakes - Added some references to Test::Class::Load in the main Test::Class POD - Added more modules that use Test::Class to SEE ALSO 0.15 - or the "down. down. deeper and down" release [2006-10-03] - Now works with Test::Deep, which annoyingly defines its own isa() subroutine. This no longer confuses Test::Class into thinking Test::Deep isa Test::Class. - Added some more modules that use Test::Class to SEE ALSO 0.14 - or the "for the Windows folk" release [2006-10-02] - Test::Class::Load now works on Windows (thanks Kenichi Ishigaki for the patch) - Tests should now pass on Windows (thanks Kenichi Ishigaki again!) 0.13 - or the "just to make Ovid & David happy" release [2006-09-29] - Added Test::Class::Load (thanks Ovid) to allow you to easily load test classes - Added ability to run a specific test or set of tests based upon a regular expression specified in the TEST_METHOD environment variable (thanks to Ovid again). This mechanism is likely to change in the future but it's useful enough to go in now. - Fixed some broken code in the POD (thanks Jeff Deifik) - Removed Cwd from prerequisites - it's core 0.12 - or the "to avoid public mocking" release [2006-09-29] - Fixed the installation errors that everybody has been rightly complaining about for the last year: - Prerequisities in requires, not build_requires - Tests no longer rely on hard coded test output (thanks Mart’n Ferrari and Nicholas Clark for patches) - Require appropriate version of Test::Exception - Added link to del.icio.us perl+testing links in POD - Fixed some bad markup in the POD - Stuck distribution related tests under t/developer - Added Perl::Critic tests under t/developer - Added some documentation for Test::Class::MethodInfo since I was bored with people asking what it was for (it's internal - don't use it) - Added a whole bunch of people to the acknowledgements section 0.11 [2005-02-19] - A belated thank you added to some folk who send in RT bugs and whose name I missed off the acknowledgements section - Tweaked link to XUL::Node in SEE ALSO - Changed RT link so it went directly to Test::Class page - An exception in a startup method now causes the rest of the tests in the current test object to be ignored, and no longer gives a bogus warning (reported by Emil Jansson - ta!) - Added COMMUNITY section to POD 0.10 [2005-02-03] - Really fixed the _test_classes bug (doh!) - Added :Tests attribute that acts like :Test but defaults to 'no_plan' if no test number is given. 0.09 [2005-01-30] - Fixed bug with _test_classes spotted by Corion's cpan smoker (see t/test_classes.t) - Added links to tada to do list to TO DO section of POD - Added links modules that use Test::Class to SEE ALSO section of POD (thanks to Terrence Brannon for suggesting this) 0.08 [2005-01-27] - The undocumented behaviour of C has been tweaked and documented. You can now run all loaded test classes by doing Test::Class->runtests - Removed undocumented autorun method, and replaced with SKIP_CLASS. This allows you to prevent test classes being run by runtests. - Removed undocumented class method run_all_tests. (thanks to David Wheeler & Ovid for helping define the above behaviour) 0.07 [2005-01-03] - Removed Test::Class::Tutorial & Test::Class::BaseTest since they shouldn't have escaped into the wild quite yet. Oops. 0.06 [2004-09-06] - Some cosmetic POD updates 0.06_8 [????-??-??] - Made tests pass with Test::Simple 0.48 - New signature since old one about to be revoked 0.06_7 [2004-06-19] - Added Module::Build support 0.06_6 [2004-03-28] - Fixed bogus test failures under MSWin32 0.06_5 [2004-02-21] - Cleaned up internals - Having a single method be simultaniously a setup and teardown method no longer supported - The undocumented add_method method, that you should not have been using anyway, disappears 0.06_4 [2004-02-13] - Fixed bogus heading styles in POD - Test names that default to $self->current_method now replace all "_" characters with spaces to increase readability - Documented default test name behaviour - D'oh! Fixed MANIFEST so the distribution actually included the new tests for 0.06_3 and 0.06_2 0.06_3 [2004-02-04] - more POD tweaks - all tests now compile with warnings enabled - test name now defaults to $self->current_method 0.06_2 [2004-01-30] - now uses inside out objects so restriction on using -test and _test as hash keys has been removed - tweaked POD of Test::Class - you can now have spaces around test numbers, etc. (bug report and patch from David Wheeler) 0.06_1 [2004-01-23] - removed examples directory from distribution, needs rewrite - removed .svn directories from distribution (doh!) - removed Test::Class::Tutorial from distribution - needs rewrite - removed Test::Class::BaseTest - needs rethink - cleaned up Test::Class POD a bit - documented.t now uses Test::Pod::Coverage if available - pod.t now uses Test::Pod if available - private methods now called as functions to avoid problems with subclasses accidentally overriding 0.05 (not distributed on CPAN) [????-??-??] - fixed MANIFEST and MANIFEST.SKIP - now skips rest of tests in a test method after first failure due to an exception. 0.04 (not distributed on CPAN) [????-??-??] - refactored mercylessly - Added Test::Class::MethodInfo - Added first draft of Test::Class::Tutorial. Feedback welcome. - rearranged Test::Class POD (hopefully making it clearer!) - dropped total_num_tests, teardown_methods, setup_methods and test_methods from public interface - they were implementation details that shouldn't have been public in first place. If you disagree let me know (with a rationale) and I'll probably add them back :-) - fixed bug where runtests() could blow up if supplied with a non-Test::Class - fixed bug where runtests returned whether all tests had passed, rather than whether all test run on test object passed - bug with runtests showing duplicate header lines fixed (thanks to Michael for adding has_plan() to Test::Builder) - FAIL_ALL now exits with the # tests failed (or 254 if more than 254 tests failed) to match behaviour of Test::Simple et al. - An extra exception thrown after all the tests in a method have run now causes a failed test (to better match the behaviour of a die at the end of a normal test script). - Changed diagnostic messages when exceptions occur to show method exception occurred in. Makes tracking failure easier. - Added Test::Class::BaseTest - base class for creating a fixture and testing it's of the correct class. - Diagnostic messages improved - Plan correctly shown when setup/teardown method without any tests throws an exception - TEST_VERBOSE now outputs a newline before the method name which makes reading verbose output easier. - Added startup and shutdown methods after suggestion from Tony Bowden. - Added run_all_classes and autorun - inspired by comments from Tony Bowden on running multiple Test::Classes easily - Changed runtests so that it will run all of a classes autorunnable sub-classes if called as a class method with no arguments. 0.03 Thu Jun 20 [2002-06-20] - fixed README - fixed tests that broke now Test::Builder (quite rightly) can no longer display multiple plans in v0.15 - tidied up the code a little. 0.02 Sat Jun 15 [2002-06-15] - released to perl-qa@perl.org 0.01 Fri May 10 22:36:52 2002 - original version; created by h2xs 1.21 with options -AX -n Test::Class Test-Class-0.50/MANIFEST000644 000766 000024 00000002734 12534705537 015045 0ustar00etherstaff000000 000000 Changes lib/Test/Class.pm lib/Test/Class/Load.pm lib/Test/Class/MethodInfo.pm Makefile.PL MANIFEST META.json META.yml README t/00-load.t t/20-load-classes.t t/21-load-subclassed.t t/_new.t t/bad-autoloads.t t/bailout.t t/builder.t t/compile.t t/current_method.t t/diag_on_failure.t t/die-in-setup.t t/die_before_plan.t t/expected_tests.t t/fail1.t t/fail2.t t/fail3.t t/filter.t t/filter_bad_filter.t t/filter_fixtures.t t/filter_fixtures_only.t t/filter_multiple.t t/header.t t/late_header.t t/methodinfo.t t/named_test.t t/num_method_tests.t t/num_tests.t t/override.t t/rt15870.t t/rt17264.t t/run_all_tests.t t/runtests.t t/runtests_die.t t/runtests_die_empty.t t/runtests_die_nearlyempty.t t/runtests_extra.t t/runtests_noplan.t t/runtests_of.t t/runtests_result.t t/runtests_return.t t/runtests_trailing.t t/runtests_with_wrong_class.t t/show_plan_in_shutdown.t t/skip1.t t/skip2.t t/skip_class_reason.t t/skip_empty_classes.t t/spaces.t t/startup.t t/startup_that_dies.t t/teardown-when-test-dies.t t/test-libs/fail/MyFail.pm t/test-libs/lib1/Tests/Foo.pm t/test-libs/lib1/Tests/Foo/Bar.pm t/test-libs/lib2/MyTest/Baz.pm t/test-libs/lib3/Tests/Bad1.pm t/test-libs/lib3/Tests/Good1.pm t/test-libs/lib3/Tests/Good2.pm t/test-libs/lib3/Tests/Subdir/Bad2.pm t/test-libs/lib3/Tests/Subdir/Good3.pm t/test_classes.t t/test_deep.t t/test_method.t t/test_verbose.t t/TestClassLoadSubclass.pm t/Tests.t t/todo.t xt/documented.t xt/meta.t xt/perlcritic.t xt/perlcriticrc xt/pmv.t xt/pod.t xt/spelling.t Test-Class-0.50/META.json000600 000766 000024 00000005515 12534705543 015322 0ustar00etherstaff000000 000000 { "abstract" : "Easily create test classes in an xUnit/JUnit style", "author" : [ "Adrian Howard , Curtis \"Ovid\" Poe, , Mark Morgan " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.052, CPAN::Meta::Converter version 2.150004", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Test-Class", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : {} }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Attribute::Handlers" : "0.77", "Carp" : "0", "File::Find" : "0", "File::Spec" : "0", "MRO::Compat" : "0.11", "Module::Runtime" : "0", "Storable" : "2.04", "Test::Builder" : "0.78", "Test::Builder::Tester" : "1.02", "Test::Simple" : "0.78", "Try::Tiny" : "0", "constant" : "0", "perl" : "5.008001", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "Fcntl" : "0", "IO::File" : "1.09", "Test" : "0", "Test::Exception" : "0.25", "Test::More" : "0.78", "base" : "0", "overload" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-Test-Class@rt.cpan.org", "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Test-Class" }, "repository" : { "type" : "git", "url" : "https://github.com/adrianh/test-class.git", "web" : "https://github.com/adrianh/test-class" } }, "version" : "0.50", "x_IRC" : "irc://irc.perl.org/#perl-qa", "x_MailingList" : "http://lists.perl.org/list/perl-qa.html", "x_contributors" : [ "Adrian Howard ", "Karen Etheridge ", "Curtis Poe ", "makk384 ", "Ricardo Signes ", "Alexandr Ciornii ", "Tim Vroom ", "Matthew Horsfall ", "Michael G. Schwern ", "Chad Granum ", "Peter Sergeant ", "Sam Kington ", "Klaus S. Madsen ", "Zefram ", "Kent Fredric " ], "x_serialization_backend" : "JSON::PP version 2.27300" } Test-Class-0.50/META.yml000600 000766 000024 00000003535 12534705543 015152 0ustar00etherstaff000000 000000 --- abstract: 'Easily create test classes in an xUnit/JUnit style' author: - 'Adrian Howard , Curtis "Ovid" Poe, , Mark Morgan ' build_requires: Fcntl: '0' IO::File: '1.09' Test: '0' Test::Exception: '0.25' Test::More: '0.78' base: '0' overload: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.052, CPAN::Meta::Converter version 2.150004' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Test-Class no_index: directory: - t - inc requires: Attribute::Handlers: '0.77' Carp: '0' File::Find: '0' File::Spec: '0' MRO::Compat: '0.11' Module::Runtime: '0' Storable: '2.04' Test::Builder: '0.78' Test::Builder::Tester: '1.02' Test::Simple: '0.78' Try::Tiny: '0' constant: '0' perl: '5.008001' strict: '0' warnings: '0' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Test-Class repository: https://github.com/adrianh/test-class.git version: '0.50' x_IRC: irc://irc.perl.org/#perl-qa x_MailingList: http://lists.perl.org/list/perl-qa.html x_contributors: - 'Adrian Howard ' - 'Karen Etheridge ' - 'Curtis Poe ' - 'makk384 ' - 'Ricardo Signes ' - 'Alexandr Ciornii ' - 'Tim Vroom ' - 'Matthew Horsfall ' - 'Michael G. Schwern ' - 'Chad Granum ' - 'Peter Sergeant ' - 'Sam Kington ' - 'Klaus S. Madsen ' - 'Zefram ' - 'Kent Fredric ' x_serialization_backend: 'CPAN::Meta::YAML version 0.016' Test-Class-0.50/Makefile.PL000644 000766 000024 00000012243 12534704460 015654 0ustar00etherstaff000000 000000 use strict; use warnings; require 5.008001; use ExtUtils::MakeMaker; my $developer = -f '.gitignore'; ExtUtils::MakeMaker->VERSION(6.98) if $developer; my %WriteMakefileArgs = ( NAME => 'Test::Class', VERSION_FROM => 'lib/Test/Class.pm', ABSTRACT_FROM => 'lib/Test/Class.pm', AUTHOR => 'Adrian Howard , Curtis "Ovid" Poe, , Mark Morgan ', LICENSE => 'perl_5', META_MERGE => { 'meta-spec' => { version => 2 }, dynamic_config => 1, resources => { repository => { url => 'https://github.com/adrianh/test-class.git', web => 'https://github.com/adrianh/test-class', type => 'git', }, bugtracker => { mailto => 'bug-Test-Class@rt.cpan.org', web => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Test-Class', }, }, x_contributors => [ # manually added, from git shortlog -e -s -n 'Adrian Howard ', 'Karen Etheridge ', 'Curtis Poe ', 'makk384 ', 'Ricardo Signes ', 'Alexandr Ciornii ', 'Tim Vroom ', 'Matthew Horsfall ', 'Michael G. Schwern ', 'Chad Granum ', 'Peter Sergeant ', 'Sam Kington ', 'Klaus S. Madsen ', 'Zefram ', 'Kent Fredric ', ], x_MailingList => 'http://lists.perl.org/list/perl-qa.html', x_IRC => 'irc://irc.perl.org/#perl-qa', }, META_ADD => { prereqs => { configure => { requires => { 'ExtUtils::MakeMaker' => '0', }, }, runtime => { requires => { 'perl' => '5.008001', 'Attribute::Handlers' => '0.77', 'MRO::Compat' => '0.11', 'Storable' => '2.04', 'Test::Simple' => '0.78', 'Test::Builder' => '0.78', 'Test::Builder::Tester' => '1.02', 'Carp' => '0', 'File::Find' => '0', 'File::Spec' => '0', 'constant' => '0', 'strict' => '0', 'warnings' => '0', 'Try::Tiny' => '0', 'Module::Runtime' => '0', }, }, test => { requires => { 'Test::Exception' => '0.25', 'IO::File' => '1.09', 'Test::More' => '0.78', 'Fcntl' => '0', 'Test' => '0', 'base' => '0', 'overload' => '0', }, }, }, }, ); my $eumm_version = eval $ExtUtils::MakeMaker::VERSION; for (qw(configure build test runtime)) { my $key = $_ eq 'runtime' ? 'PREREQ_PM' : uc $_.'_REQUIRES'; next unless exists $WriteMakefileArgs{META_ADD}{prereqs}{$_} or exists $WriteMakefileArgs{$key}; my $r = $WriteMakefileArgs{$key} = { %{$WriteMakefileArgs{META_ADD}{prereqs}{$_}{requires} || {}}, %{delete $WriteMakefileArgs{$key} || {}}, }; defined $r->{$_} or delete $r->{$_} for keys %$r; } # dynamic prereqs get added here. # 0.99 broke test_out with qr// $WriteMakefileArgs{PREREQ_PM}{'Test::Builder'} = '1.001002' if eval { require Test::Builder; Test::Builder->VERSION eq '0.99' }; $WriteMakefileArgs{MIN_PERL_VERSION} = delete $WriteMakefileArgs{PREREQ_PM}{perl} || 0; die 'attention developer: you need to do a sane meta merge here!' if keys %{$WriteMakefileArgs{BUILD_REQUIRES}}; $WriteMakefileArgs{BUILD_REQUIRES} = { %{$WriteMakefileArgs{BUILD_REQUIRES} || {}}, %{delete $WriteMakefileArgs{TEST_REQUIRES}} } if $eumm_version < 6.63_03; $WriteMakefileArgs{PREREQ_PM} = { %{$WriteMakefileArgs{PREREQ_PM}}, %{delete $WriteMakefileArgs{BUILD_REQUIRES}} } if $eumm_version < 6.55_01; delete $WriteMakefileArgs{CONFIGURE_REQUIRES} if $eumm_version < 6.51_03; delete $WriteMakefileArgs{MIN_PERL_VERSION} if $eumm_version < 6.48; delete @WriteMakefileArgs{qw(META_ADD META_MERGE)} if $eumm_version < 6.46; delete $WriteMakefileArgs{LICENSE} if $eumm_version < 6.31; WriteMakefile(%WriteMakefileArgs); use Config; system("$Config{bin}/pod2text $WriteMakefileArgs{VERSION_FROM} > README") if $developer and (not -e 'README' or (stat('README'))[9] < (stat($WriteMakefileArgs{VERSION_FROM}))[9]); Test-Class-0.50/README000644 000766 000024 00000146220 12534703177 014571 0ustar00etherstaff000000 000000 NAME Test::Class - Easily create test classes in an xUnit/JUnit style VERSION version 0.50 SYNOPSIS package Example::Test; use base qw(Test::Class); use Test::More; # setup methods are run before every test method. sub make_fixture : Test(setup) { my $array = [1, 2]; shift->{test_array} = $array; } # a test method that runs 1 test sub test_push : Test { my $array = shift->{test_array}; push @$array, 3; is_deeply($array, [1, 2, 3], 'push worked'); } # a test method that runs 4 tests sub test_pop : Test(4) { my $array = shift->{test_array}; is(pop @$array, 2, 'pop = 2'); is(pop @$array, 1, 'pop = 1'); is_deeply($array, [], 'array empty'); is(pop @$array, undef, 'pop = undef'); } # teardown methods are run after every test method. sub teardown : Test(teardown) { my $array = shift->{test_array}; diag("array = (@$array) after test(s)"); } later in a nearby .t file #! /usr/bin/perl use Example::Test; # run all the test methods in Example::Test Test::Class->runtests; Outputs: 1..5 ok 1 - pop = 2 ok 2 - pop = 1 ok 3 - array empty ok 4 - pop = undef # array = () after test(s) ok 5 - push worked # array = (1 2 3) after test(s) DESCRIPTION Test::Class provides a simple way of creating classes and objects to test your code in an xUnit style. Built using Test::Builder, it was designed to work with other Test::Builder based modules (Test::More, Test::Differences, Test::Exception, etc.). *Note:* This module will make more sense, if you are already familiar with the "standard" mechanisms for testing perl code. Those unfamiliar with Test::Harness, Test::Simple, Test::More and friends should go take a look at them now. Test::Tutorial is a good starting point. INTRODUCTION A brief history lesson In 1994 Kent Beck wrote a testing framework for Smalltalk called SUnit. It was popular. You can read a copy of his original paper at . Later Kent Beck and Erich Gamma created JUnit for testing Java . It was popular too. Now there are xUnit frameworks for every language from Ada to XSLT. You can find a list at . While xUnit frameworks are traditionally associated with unit testing they are also useful in the creation of functional/acceptance tests. Test::Class is (yet another) implementation of xUnit style testing in Perl. Why you should use Test::Class Test::Class attempts to provide simple xUnit testing that integrates simply with the standard perl *.t style of testing. In particular: * All the advantages of xUnit testing. You can easily create test fixtures and isolate tests. It provides a framework that should be familiar to people who have used other xUnit style test systems. * It is built with Test::Builder and should co-exist happily with all other Test::Builder based modules. This makes using test classes in *.t scripts, and refactoring normal tests into test classes, much simpler because: * You do not have to learn a new set of new test APIs and can continue using ok(), like(), etc. from Test::More and friends. * Skipping tests and todo tests are supported. * You can have normal tests and Test::Class classes co-existing in the same *.t script. You don't have to re-write an entire script, but can use test classes as and when it proves useful. * You can easily package your tests as classes/modules, rather than *.t scripts. This simplifies reuse, documentation and distribution, encourages refactoring, and allows tests to be extended by inheritance. * You can have multiple setup/teardown methods. For example have one teardown method to clean up resources and another to check that class invariants still hold. * It can make running tests faster. Once you have refactored your *.t scripts into classes they can be easily run from a single script. This gains you the (often considerable) start up time that each separate *.t script takes. Why you should *not* use Test::Class * If your *.t scripts are working fine then don't bother with Test::Class. For simple test suites it is almost certainly overkill. Don't start thinking about using Test::Class until issues like duplicate code in your test scripts start to annoy. * If you are distributing your code it is yet another module that the user has to have to run your tests (unless you distribute it with your test suite of course). * If you are used to the TestCase/Suite/Runner class structure used by JUnit and similar testing frameworks you may find Test::Unit more familiar (but try reading "HELP FOR CONFUSED JUNIT USERS" before you give up). TEST CLASSES A test class is just a class that inherits from Test::Class. Defining a test class is as simple as doing: package Example::Test; use base qw(Test::Class); Since Test::Class does not provide its own test functions, but uses those provided by Test::More and friends, you will nearly always also want to have: use Test::More; to import the test functions into your test class. METHOD TYPES There are three different types of method you can define using Test::Class. 1) Test methods You define test methods using the Test attribute. For example: package Example::Test; use base qw(Test::Class); use Test::More; sub subtraction : Test { is( 2-1, 1, 'subtraction works' ); } This declares the "subtraction" method as a test method that runs one test. If your test method runs more than one test, you should put the number of tests in brackets like this: sub addition : Test(2) { is(10 + 20, 30, 'addition works'); is(20 + 10, 30, ' both ways'); } If you don't know the number of tests at compile time you can use "no_plan" like this. sub check_class : Test(no_plan) { my $objects = shift->{objects}; isa_ok($_, "Object") foreach @$objects; } or use the :Tests attribute, which acts just like ":Test" but defaults to "no_plan" if no number is given: sub check_class : Tests { my $objects = shift->{objects}; isa_ok($_, "Object") foreach @$objects; } 2) Setup and teardown methods Setup and teardown methods are run before and after every test. For example: sub before : Test(setup) { diag("running before test") } sub after : Test(teardown) { diag("running after test") } You can use setup and teardown methods to create common objects used by all of your test methods (a test *fixture*) and store them in your Test::Class object, treating it as a hash. For example: sub pig : Test(setup) { my $self = shift; $self->{test_pig} = Pig->new; } sub born_hungry : Test { my $pig = shift->{test_pig}; is($pig->hungry, 'pigs are born hungry'); } sub eats : Test(3) { my $pig = shift->{test_pig}; ok( $pig->feed, 'pig fed okay'); ok(! $pig->hungry, 'fed pig not hungry'); ok(! $pig->feed, 'cannot feed full pig'); } You can also declare setup and teardown methods as running tests. For example you could check that the test pig survives each test method by doing: sub pig_alive : Test(teardown => 1) { my $pig = shift->{test_pig}; ok($pig->alive, 'pig survived tests' ); } 3) Startup and shutdown methods Startup and shutdown methods are like setup and teardown methods for the whole test class. All the startup methods are run once when you start running a test class. All the shutdown methods are run once just before a test class stops running. You can use these to create and destroy expensive objects that you don't want to have to create and destroy for every test - a database connection for example: sub db_connect : Test(startup) { shift->{dbi} = DBI->connect; } sub db_disconnect : Test(shutdown) { shift->{dbi}->disconnect; } Just like setup and teardown methods you can pass an optional number of tests to startup and shutdown methods. For example: sub example : Test(startup => 1) { ok(1, 'a startup method with one test'); } If you want to run an unknown number of tests within your startup method, you need to say e.g. sub example : Test(startup => no_plan) { ok(1, q{The first of many tests that don't want to have to count}); ... } as the : Tests attribute behaves exactly like : Test in this context. If a startup method has a failing test or throws an exception then all other tests for the current test object are ignored. RUNNING TESTS You run test methods with runtests(). Doing: Test::Class->runtests runs all of the test methods in every loaded test class. This allows you to easily load multiple test classes in a *.t file and run them all. #! /usr/bin/perl # load all the test classes I want to run use Foo::Test; use Foo::Bar::Test; use Foo::Fribble::Test; use Foo::Ni::Test; # and run them all Test::Class->runtests; You can use Test::Class::Load to automatically load all the test classes in a given set of directories. If you need finer control you can create individual test objects with new(). For example to just run the tests in the test class "Foo::Bar::Test" you can do: Example::Test->new->runtests You can also pass runtests() a list of test objects to run. For example: my $o1 = Example::Test->new; my $o2 = Another::Test->new; # runs all the tests in $o1 and $o2 $o1->runtests($o2); Since, by definition, the base Test::Class has no tests, you could also have written: my $o1 = Example::Test->new; my $o2 = Another::Test->new; Test::Class->runtests($o1, $o2); If you pass runtests() class names it will automatically create test objects for you, so the above can be written more compactly as: Test::Class->runtests(qw( Example::Test Another::Test )) In all of the above examples runtests() will look at the number of tests both test classes run and output an appropriate test header for Test::Harness automatically. What happens if you run test classes and normal tests in the same script? For example: Test::Class->runtests; ok(Example->new->foo, 'a test not in the test class'); ok(Example->new->bar, 'ditto'); Test::Harness will complain that it saw more tests than it expected since the test header output by runtests() will not include the two normal tests. To overcome this problem you can pass an integer value to runtests(). This is added to the total number of tests in the test header. So the problematic example can be rewritten as follows: Test::Class->runtests(+2); ok(Example->new->foo, 'a test not in the test class'); ok(Example->new->bar, 'ditto'); If you prefer to write your test plan explicitly you can use expected_tests() to find out the number of tests a class/object is expected to run. Since runtests() will not output a test plan if one has already been set, the previous example can be written as: plan tests => Test::Class->expected_tests(+2); Test::Class->runtests; ok(Example->new->foo, 'a test not in the test class'); ok(Example->new->bar, 'ditto'); *Remember:* Test objects are just normal perl objects. Test classes are just normal perl classes. Setup, test and teardown methods are just normal methods. You are completely free to have other methods in your class that are called from your test methods, or have object specific "new" and "DESTROY" methods. In particular you can override the new() method to pass parameters to your test object, or re-define the number of tests a method will run. See num_method_tests() for an example. TEST DESCRIPTIONS The test functions you import from Test::More and other Test::Builder based modules usually take an optional third argument that specifies the test description, for example: is $something, $something_else, 'a description of my test'; If you do not supply a test description, and the test function does not supply its own default, then Test::Class will use the name of the currently running test method, replacing all "_" characters with spaces so: sub one_plus_one_is_two : Test { is 1+1, 2; } will result in: ok 1 - one plus one is two RUNNING ORDER OF METHODS Methods of each type are run in the following order: 1. All of the startup methods in alphabetical order 2. For each test method, in alphabetical order: * All of the setup methods in alphabetical order * The test method. * All of the teardown methods in alphabetical order 3. All of the shutdown methods in alphabetical order. Most of the time you should not care what order tests are run in, but it can occasionally be useful to force some test methods to be run early. For example: sub _check_new { my $self = shift; isa_ok(Object->new, "Object") or $self->BAILOUT('new fails!'); } The leading "_" will force the above method to run first - allowing the entire suite to be aborted before any other test methods run. HANDLING EXCEPTIONS If a startup, setup, test, teardown or shutdown method dies then runtests() will catch the exception and fail any remaining test. For example: sub test_object : Test(2) { my $object = Object->new; isa_ok( $object, "Object" ) or die "could not create object\n"; ok( $object->open, "open worked" ); } will produce the following if the first test failed: not ok 1 - The object isa Object # Failed test 'The object isa Object' # at /Users/adrianh/Desktop/foo.pl line 14. # (in MyTest->test_object) # The object isn't defined not ok 2 - test_object died (could not create object) # Failed test 'test_object died (could not create object)' # at /Users/adrianh/Desktop/foo.pl line 19. # (in MyTest->test_object) This can considerably simplify testing code that throws exceptions. Rather than having to explicitly check that the code exited normally (e.g. with "lives_ok" in Test::Exception) the test will fail automatically - without aborting the other test methods. For example contrast: use Test::Exception; my $file; lives_ok { $file = read_file('test.txt') } 'file read'; is($file, "content", 'test file read'); with: sub read_file : Test { is(read_file('test.txt'), "content", 'test file read'); } If more than one test remains after an exception then the first one is failed, and the remaining ones are skipped. If the setup method of a test method dies, then all of the remaining setup and shutdown methods are also skipped. Since startup methods will usually be creating state needed by all the other test methods, an exception within a startup method will prevent all other test methods of that class running. RETURNING EARLY If a test method returns before it has run all of its tests, by default the missing tests are deemed to have been skipped; see "Skipped Tests" for more information. However, if the class's "fail_if_returned_early" method returns true, then the missing tests will be deemed to have failed. For example, package MyClass; use base 'Test::Class'; sub fail_if_returned_early { 1 } sub oops : Tests(8) { for (my $n=1; $n*$n<50; ++$n) { ok 1, "$n squared is less than fifty"; } } SKIPPED TESTS You can skip the rest of the tests in a method by returning from the method before all the test have finished running (but see "Returning Early" for how to change this). The value returned is used as the reason for the tests being skipped. This makes managing tests that can be skipped for multiple reasons very simple. For example: sub flying_pigs : Test(5) { my $pig = Pig->new; isa_ok($pig, 'Pig') or return("cannot breed pigs") can_ok($pig, 'takeoff') or return("pigs don't fly here"); ok($pig->takeoff, 'takeoff') or return("takeoff failed"); ok( $pig->altitude > 0, 'Pig is airborne' ); ok( $pig->airspeed > 0, ' and moving' ); } If you run this test in an environment where "Pig->new" worked and the takeoff method existed, but failed when ran, you would get: ok 1 - The object isa Pig ok 2 - can takeoff not ok 3 - takeoff ok 4 # skip takeoff failed ok 5 # skip takeoff failed You can also skip tests just as you do in Test::More or Test::Builder - see "Conditional tests" in Test::More for more information. *Note:* if you want to skip tests in a method with "no_plan" tests then you have to explicitly skip the tests in the method - since Test::Class cannot determine how many tests (if any) should be skipped: sub test_objects : Tests { my $self = shift; my $objects = $self->{objects}; if (@$objects) { isa_ok($_, "Object") foreach (@$objects); } else { $self->builder->skip("no objects to test"); } } Another way of overcoming this problem is to explicitly set the number of tests for the method at run time using num_method_tests() or "num_tests". You can make a test class skip all of its tests by setting SKIP_CLASS() before runtests() is called. TO DO TESTS You can create todo tests just as you do in Test::More and Test::Builder using the $TODO variable. For example: sub live_test : Test { local $TODO = "live currently unimplemented"; ok(Object->live, "object live"); } See "Todo tests" in Test::Harness for more information. EXTENDING TEST CLASSES BY INHERITANCE You can extend test methods by inheritance in the usual way. For example consider the following test class for a "Pig" object. package Pig::Test; use base qw(Test::Class); use Test::More; sub testing_class { "Pig" } sub new_args { (-age => 3) } sub setup : Test(setup) { my $self = shift; my $class = $self->testing_class; my @args = $self->new_args; $self->{pig} = $class->new( @args ); } sub _creation : Test { my $self = shift; isa_ok($self->{pig}, $self->testing_class) or $self->FAIL_ALL('Pig->new failed'); } sub check_fields : Test { my $pig = shift->{pig} is($pig->age, 3, "age accessed"); } Next consider "NamedPig" a subclass of "Pig" where you can give your pig a name. We want to make sure that all the tests for the "Pig" object still work for "NamedPig". We can do this by subclassing "Pig::Test" and overriding the "testing_class" and "new_args" methods. package NamedPig::Test; use base qw(Pig::Test); use Test::More; sub testing_class { "NamedPig" } sub new_args { (shift->SUPER::new_args, -name => 'Porky') } Now we need to test the name method. We could write another test method, but we also have the option of extending the existing "check_fields" method. sub check_fields : Test(2) { my $self = shift; $self->SUPER::check_fields; is($self->{pig}->name, 'Porky', 'name accessed'); } While the above works, the total number of tests for the method is dependent on the number of tests in its "SUPER::check_fields". If we add a test to "Pig::Test->check_fields" we will also have to update the number of tests of "NamedPig::test->check_fields". Test::Class allows us to state explicitly that we are adding tests to an existing method by using the "+" prefix. Since we are adding a single test to "check_fields", it can be rewritten as: sub check_fields : Test(+1) { my $self = shift; $self->SUPER::check_fields; is($self->{pig}->name, 'Porky', 'name accessed'); } With the above definition you can add tests to "check_fields" in "Pig::Test" without affecting "NamedPig::Test". RUNNING INDIVIDUAL TESTS NOTE: The exact mechanism for running individual tests is likely to change in the future. Sometimes you just want to run a single test. Commenting out other tests or writing code to skip them can be a hassle, so you can specify the "TEST_METHOD" environment variable. The value is expected to be a valid regular expression and, if present, only runs test methods whose names match the regular expression. Startup, setup, teardown and shutdown tests will still be run. One easy way of doing this is by specifying the environment variable *before* the "runtests" method is called. Running a test named "customer_profile": #! /usr/bin/perl use Example::Test; $ENV{TEST_METHOD} = 'customer_profile'; Test::Class->runtests; Running all tests with "customer" in their name: #! /usr/bin/perl use Example::Test; $ENV{TEST_METHOD} = '.*customer.*'; Test::Class->runtests; If you specify an invalid regular expression, your tests will not be run: #! /usr/bin/perl use Example::Test; $ENV{TEST_METHOD} = 'C++'; Test::Class->runtests; And when you run it: TEST_METHOD (C++) is not a valid regular expression: Search pattern \ not terminated at (eval 17) line 1. ORGANISING YOUR TEST CLASSES You can, of course, organise your test modules as you wish. My personal preferences is: * Name test classes with a suffix of "::Test" so the test class for the "Foo::Bar" module would be "Foo::Bar::Test". * Place all test classes in t/lib. The Test::Class::Load provides a simple mechanism for easily loading all of the test classes in a given set of directories. A NOTE ON LOADING TEST CLASSES Due to its use of subroutine attributes Test::Class based modules must be loaded at compile rather than run time. This is because the :Test attribute is applied by a CHECK block. This can be problematic if you want to dynamically load Test::Class modules. Basically while: require $some_test_class; will break, doing: BEGIN { require $some_test_class } will work just fine. For more information on CHECK blocks see "BEGIN, CHECK, INIT and END" in perlmod. If you still can't arrange for your classes to be loaded at runtime, you could use an alternative mechanism for adding your tests: # sub test_something : Test(3) {...} # becomes sub test_something {...} __PACKAGE__->add_testinfo('test_something', test => 3); See the add_testinfo method for more details. Additionally, if you've forgotten to enable warnings and have two test subs called the same thing, you will get the same error. GENERAL FILTERING OF TESTS The use of $ENV{TEST_METHOD} to run just a subset of tests is useful, but sometimes it doesn't give the level of granularity that you desire. Another feature of this class is the ability to do filtering on other static criteria. In order to permit this, a generic filtering method is supported. This can be used by specifying coderefs to the 'add_filter' method of this class. In determining which tests should be run, all filters that have previously been specified via the add_filter method will be run in-turn for each normal test method. If any of these filters return a false value, the method will not be executed, or included in the number of tests. Note that filters will only be run for normal test methods, they are ignored for startup, shutdown, setup, and teardown test methods. Note that test filters are global, and will affect all tests in all classes, not just the one that they were defined in. An example of this mechanism that mostly simulates the use of TEST_METHOD above is: package MyTests; use Test::More; use base qw( Test::Class ); my $MYTEST_METHOD = qr/^t_not_filtered$/; my $filter = sub { my ( $test_class, $test_method ) = @_; return $test_method =~ $MYTEST_METHOD; } Test::Class->add_filter( $filter ); sub t_filtered : Test( 1 ) { fail( "filtered test run" ); } sub t_not_filtered : Test( 1 ) { pass( "unfiltered test run" ); } METHODS Creating and running tests Test # test methods sub method_name : Test { ... } sub method_name : Test(N) { ... } # setup methods sub method_name : Test(setup) { ... } sub method_name : Test(setup => N) { ... } # teardown methods sub method_name : Test(teardown) { ... } sub method_name : Test(teardown => N) { ... } # startup methods sub method_name : Test(startup) { ... } sub method_name : Test(startup => N) { ... } # shutdown methods sub method_name : Test(shutdown) { ... } sub method_name : Test(shutdown => N) { ... } Marks a startup, setup, test, teardown or shutdown method. See runtests() for information on how to run methods declared with the "Test" attribute. N specifies the number of tests the method runs. * If N is an integer then the method should run exactly N tests. * If N is an integer with a "+" prefix then the method is expected to call its "SUPER::" method and extend it by running N additional tests. * If N is the string "no_plan" then the method can run an arbitrary number of tests. If N is not specified it defaults to 1 for test methods, and 0 for startup, setup, teardown and shutdown methods. You can change the number of tests that a method runs using num_method_tests() or num_tests(). Tests sub method_name : Tests { ... } sub method_name : Tests(N) { ... } Acts just like the ":Test" attribute, except that if the number of tests is not specified it defaults to "no_plan". So the following are equivalent: sub silly1 :Test( no_plan ) { ok(1) foreach (1 .. rand 5) } sub silly2 :Tests { ok(1) foreach (1 .. rand 5) } new $Tests = CLASS->new(KEY => VAL ...) $Tests2 = $Tests->new(KEY => VAL ...) Creates a new test object (blessed hashref) containing the specified key/value pairs. If called as an object method the existing object's key/value pairs are copied into the new object. Any key/value pairs passed to "new" override those in the original object if duplicates occur. Since the test object is passed to every test method as it runs, it is a convenient place to store test fixtures. For example: sub make_fixture : Test(setup) { my $self = shift; $self->{object} = Object->new(); $self->{dbh} = Mock::DBI->new(-type => normal); } sub test_open : Test { my $self = shift; my ($o, $dbh) = ($self->{object}, $self->{dbh}); ok($o->open($dbh), "opened ok"); } See num_method_tests() for an example of overriding "new". expected_tests $n = $Tests->expected_tests $n = CLASS->expected_tests $n = $Tests->expected_tests(TEST, ...) $n = CLASS->expected_tests(TEST, ...) Returns the total number of tests that runtests() will run on the specified class/object. This includes tests run by any setup and teardown methods. Will return "no_plan" if the exact number of tests is undetermined (i.e. if any setup, test or teardown method has an undetermined number of tests). The "expected_tests" of an object after runtests() has been executed will include any run time changes to the expected number of tests made by num_tests() or num_method_tests(). "expected_tests" can also take an optional list of test objects, test classes and integers. In this case the result is the total number of expected tests for all the test/object classes (including the one the method was applied to) plus any integer values. "expected_tests" is useful when you're integrating one or more test classes into a more traditional test script, for example: use Test::More; use My::Test::Class; plan tests => My::Test::Class->expected_tests(+2); ok(whatever, 'a test'); ok(whatever, 'another test'); My::Test::Class->runtests; runtests $allok = $Tests->runtests $allok = CLASS->runtests $allok = $Tests->runtests(TEST, ...) $allok = CLASS->runtests(TEST, ...) "runtests" is used to run test classes. At its most basic doing: $test->runtests will run the test methods of the test object $test, unless "$test->SKIP_CLASS" returns a true value. Unless you have already specified a test plan using Test::Builder (or Test::More, et al) "runtests" will set the test plan just before the first method that runs a test is executed. If the environment variable "TEST_VERBOSE" is set "runtests" will display the name of each test method before it runs like this: # My::Test::Class->my_test ok 1 - fribble # My::Test::Class->another_test ok 2 - bar Just like expected_tests(), "runtests" can take an optional list of test object/classes and integers. All of the test object/classes are run. Any integers are added to the total number of tests shown in the test header output by "runtests". For example, you can run all the tests in test classes A, B and C, plus one additional normal test by doing: Test::Class->runtests(qw(A B C), +1); ok(1==1, 'non class test'); Finally, if you call "runtests" on a test class without any arguments it will run all of the test methods of that class, and all subclasses of that class. For example: #! /usr/bin/perl # Test all the Foo stuff use Foo::Test; use Foo::Bar::Test; use Foo::Ni::Test; # run all the Foo*Test modules we just loaded Test::Class->runtests; SKIP_CLASS $reason = CLASS->SKIP_CLASS; CLASS->SKIP_CLASS( $reason ); Determines whether the test class CLASS should run it's tests. If SKIP_CLASS returns a true value then runtests() will not run any of the test methods in CLASS. You can override the default on a class-by-class basis by supplying a new value to SKIP_CLASS. For example if you have an abstract base class that should not run just add the following to your module: My::Abstract::Test->SKIP_CLASS( 1 ); This will not affect any sub-classes of "My::Abstract::Test" which will run as normal. If the true value returned by SKIP_CLASS is anything other than "1" then a skip test is output using this value as the skip message. For example: My::Postgres::Test->SKIP_CLASS( $ENV{POSTGRES_HOME} ? 0 : '$POSTGRES_HOME needs to be set' ); will output something like this if "POSTGRES_HOME" is not set ... other tests ... ok 123 # skip My::Postgres::Test - $POSTGRES_HOME needs to be set ... more tests ... You can also override SKIP_CLASS for a class hierarchy. For example, to prevent any subclasses of My::Postgres::Test running we could override SKIP_CLASS like this: sub My::Postgres::Test::SKIP_CLASS { $ENV{POSTGRES_HOME} ? 0 : '$POSTGRES_HOME needs to be set' } Fetching and setting a method's test number num_method_tests $n = $Tests->num_method_tests($method_name) $Tests->num_method_tests($method_name, $n) $n = CLASS->num_method_tests($method_name) CLASS->num_method_tests($method_name, $n) Fetch or set the number of tests that the named method is expected to run. If the method has an undetermined number of tests then $n should be the string "no_plan". If the method is extending the number of tests run by the method in a superclass then $n should have a "+" prefix. When called as a class method any change to the expected number of tests applies to all future test objects. Existing test objects are unaffected. When called as an object method any change to the expected number of tests applies to that object alone. "num_method_tests" is useful when you need to set the expected number of tests at object creation time, rather than at compile time. For example, the following test class will run a different number of tests depending on the number of objects supplied. package Object::Test; use base qw(Test::Class); use Test::More; sub new { my $class = shift; my $self = $class->SUPER::new(@_); my $num_objects = @{$self->{objects}}; $self->num_method_tests('test_objects', $num_objects); return($self); } sub test_objects : Tests { my $self = shift; ok($_->open, "opened $_") foreach @{$self->{objects}}; } ... # This runs two tests Object::Test->new(objects => [$o1, $o2]); The advantage of setting the number of tests at object creation time, rather than using a test method without a plan, is that the number of expected tests can be determined before testing begins. This allows better diagnostics from runtests(), Test::Builder and Test::Harness. "num_method_tests" is a protected method and can only be called by subclasses of Test::Class. It fetches or sets the expected number of tests for the methods of the class it was *called in*, not the methods of the object/class it was *applied to*. This allows test classes that use "num_method_tests" to be subclassed easily. For example, consider the creation of a subclass of Object::Test that ensures that all the opened objects are read-only: package Special::Object::Test; use base qw(Object::Test); use Test::More; sub test_objects : Test(+1) { my $self = shift; $self->SUPER::test_objects; my @bad_objects = grep {! $_->read_only} (@{$self->{objects}}); ok(@bad_objects == 0, "all objects read only"); } ... # This runs three tests Special::Object::Test->new(objects => [$o1, $o2]); Since the call to "num_method_tests" in Object::Test only affects the "test_objects" of Object::Test, the above works as you would expect. num_tests $n = $Tests->num_tests $Tests->num_tests($n) $n = CLASS->num_tests CLASS->num_tests($n) Set or return the number of expected tests associated with the currently running test method. This is the same as calling num_method_tests() with a method name of current_method(). For example: sub txt_files_readable : Tests { my $self = shift; my @files = <*.txt>; $self->num_tests(scalar(@files)); ok(-r $_, "$_ readable") foreach (@files); } Setting the number of expected tests at run time, rather than just having a "no_plan" test method, allows runtests() to display appropriate diagnostic messages if the method runs a different number of tests. Support methods builder $Tests->builder Returns the underlying Test::Builder object that Test::Class uses. For example: sub test_close : Test { my $self = shift; my ($o, $dbh) = ($self->{object}, $self->{dbh}); $self->builder->ok($o->close($dbh), "closed ok"); } current_method $method_name = $Tests->current_method $method_name = CLASS->current_method Returns the name of the test method currently being executed by runtests(), or "undef" if runtests() has not been called. The method name is also available in the setup and teardown methods that run before and after the test method. This can be useful in producing diagnostic messages, for example: sub test_invarient : Test(teardown => 1) { my $self = shift; my $m = $self->current_method; ok($self->invarient_ok, "class okay after $m"); } BAILOUT $Tests->BAILOUT($reason) CLASS->BAILOUT($reason) Things are going so badly all testing should terminate, including running any additional test scripts invoked by Test::Harness. This is exactly the same as doing: $self->builder->BAILOUT See "BAILOUT" in Test::Builder for details. Any teardown and shutdown methods are *not* run. FAIL_ALL $Tests->FAIL_ALL($reason) CLASS->FAIL_ALL($reason) Things are going so badly all the remaining tests in the current script should fail. Exits immediately with the number of tests failed, or 254 if more than 254 tests were run. Any teardown methods are *not* run. This does not affect the running of any other test scripts invoked by Test::Harness. For example, if all your tests rely on the ability to create objects then you might want something like this as an early test: sub _test_new : Test(3) { my $self = shift; isa_ok(Object->new, "Object") || $self->FAIL_ALL('cannot create Objects'); ... } SKIP_ALL $Tests->SKIP_ALL($reason) CLASS->SKIP_ALL($reason) Things are going so badly all the remaining tests in the current script should be skipped. Exits immediately with 0 - teardown methods are *not* run. This does not affect the running of any other test scripts invoked by Test::Harness. For example, if you had a test script that only applied to the darwin OS you could write: sub _darwin_only : Test(setup) { my $self = shift; $self->SKIP_ALL("darwin only") unless $^O eq "darwin"; } add_testinfo CLASS->add_testinfo($name, $type, $num_tests) Chiefly for use by libraries like Test::Class::Sugar, which can't use the ":Test(...)" interfaces make test methods. "add_testinfo" informs the class about a test method that has been defined without a "Test", "Tests" or other attribute. $name is the name of the method, $type must be one of "startup", "setup", "test", "teardown" or "shutdown", and $num_tests has the same meaning as "N" in the description of the Test attribute. add_filter CLASS->add_filter($filter_coderef); Adds a filtering coderef. Each filter is passed a test class and method name and returns a boolean. All filters are applied globally in the order they were added. If any filter returns false the test method is not run or included in the number of tests. Note that filters will only be run for normal test methods, they are ignored for startup, shutdown, setup, and teardown test methods. See the section on the "GENERAL FILTERING OF TESTS" for more information. fail_if_returned_early Controls what happens if a method returns before it has run all of its tests. It is called with no arguments in boolean context; if it returns true, then the missing tests fail, otherwise, they skip. See "Returning Early" and "Skipped Tests". HELP FOR CONFUSED JUNIT USERS This section is for people who have used JUnit (or similar) and are confused because they don't see the TestCase/Suite/Runner class framework they were expecting. Here we take each of the major classes in JUnit and compare them with their equivalent Perl testing modules. Class Assert The test assertions provided by Assert correspond to the test functions provided by the Test::Builder based modules (Test::More, Test::Exception, Test::Differences, etc.) Unlike JUnit the test functions supplied by Test::More et al do *not* throw exceptions on failure. They just report the failure to STDOUT where it is collected by Test::Harness. This means that where you have sub foo : Test(2) { ok($foo->method1); ok($foo->method2); } The second test *will* run if the first one fails. You can emulate the JUnit way of doing it by throwing an explicit exception on test failure: sub foo : Test(2) { ok($foo->method1) or die "method1 failed"; ok($foo->method2); } The exception will be caught by Test::Class and the other test automatically failed. Class TestCase Test::Class corresponds to TestCase in JUnit. In Test::Class setup, test and teardown methods are marked explicitly using the Test attribute. Since we need to know the total number of tests to provide a test plan for Test::Harness, we also state how many tests each method runs. Unlike JUnit you can have multiple setup/teardown methods in a class. Class TestSuite Test::Class also does the work that would be done by TestSuite in JUnit. Since the methods are marked with attributes, Test::Class knows what is and isn't a test method. This allows it to run all the test methods without having the developer create a suite manually, or use reflection to dynamically determine the test methods by name. See the runtests() method for more details. The running order of the test methods is fixed in Test::Class. Methods are executed in alphabetical order. To run individual test methods, see "RUNNING INDIVIDUAL TESTS". Class TestRunner Test::Harness does the work of the TestRunner in JUnit. It collects the test results (sent to STDOUT) and collates the results. Unlike JUnit there is no distinction made by Test::Harness between errors and failures. However, it does support skipped and todo test - which JUnit does not. If you want to write your own test runners you should look at Test::Harness::Straps. OTHER MODULES FOR XUNIT TESTING IN PERL In addition to Test::Class there are two other distributions for xUnit testing in perl. Both have a longer history than Test::Class and might be more suitable for your needs. I am biased since I wrote Test::Class - so please read the following with appropriate levels of scepticism. If you think I have misrepresented the modules please let me know. Test::SimpleUnit A very simple unit testing framework. If you are looking for a lightweight single module solution this might be for you. The advantage of Test::SimpleUnit is that it is simple! Just one module with a smallish API to learn. Of course this is also the disadvantage. It's not class based so you cannot create testing classes to reuse and extend. It doesn't use Test::Builder so it's difficult to extend or integrate with other testing modules. If you are already familiar with Test::Builder, Test::More and friends you will have to learn a new test assertion API. It does not support todo tests. Test::Unit Test::Unit is a port of JUnit into perl. If you have used JUnit then the Test::Unit framework should be very familiar. It is class based so you can easily reuse your test classes and extend by subclassing. You get a nice flexible framework you can tweak to your heart's content. If you can run Tk you also get a graphical test runner. However, Test::Unit is not based on Test::Builder. You cannot easily move Test::Builder based test functions into Test::Unit based classes. You have to learn another test assertion API. Test::Unit implements it's own testing framework separate from Test::Harness. You can retrofit *.t scripts as unit tests, and output test results in the format that Test::Harness expects, but things like todo tests and skipping tests are not supported. BUGS None known at the time of writing. If you find any bugs please let me know by e-mail at , or report the problem with . COMMUNITY perl-qa If you are interested in testing using Perl I recommend you visit and join the excellent perl-qa mailing list. See for details on how to subscribe. perlmonks You can find users of Test::Class, including the module author, on . Feel free to ask questions on Test::Class there. CPAN::Forum The CPAN Forum is a web forum for discussing Perl's CPAN modules. The Test::Class forum can be found at . TO DO If you think this module should do something that it doesn't (or does something that it shouldn't) please let me know. You can see my current to do list at , with an RSS feed of changes at . ACKNOWLEDGMENTS This is yet another implementation of the ideas from Kent Beck's Testing Framework paper . Thanks to Adam Kennedy, agianni, Alexander D'Archangel, Andrew Grangaard, Apocalypse, Ask Bjorn Hansen, Chris Dolan, Chris Williams, Corion, Cosimo Streppone, Daniel Berger, Dave Evans, Dave O'Neill, David Cantrell, David Wheeler, Diab Jerius, Emil Jansson, Gunnar Wolf, Hai Pham, Hynek, imacat, Jeff Deifik, Jim Brandt, Jochen Stenzel, Johan Lindstrom, John West, Jonathan R. Warden, Joshua ben Jore, Jost Krieger, Ken Fox, Kenichi Ishigaki Lee Goddard, Mark Morgan, Mark Reynolds, Mark Stosberg, Martin Ferrari, Mathieu Sauve-Frankel, Matt Trout, Matt Williamson, Michael G Schwern, Murat Uenalan, Naveed Massjouni, Nicholas Clark, Ovid, Piers Cawley, Rob Kinyon, Sam Raymer, Scott Lanning, Sebastien Aperghis-Tramoni, Steve Kirkup, Stray Toaster, Ted Carnahan, Terrence Brannon, Todd W, Tom Metro, Tony Bowden, Tony Edwardson, William McKee, various anonymous folk and all the fine people on perl-qa for their feedback, patches, suggestions and nagging. This module wouldn't be possible without the excellent Test::Builder. Thanks to chromatic and Michael G Schwern for creating such a useful module. AUTHORS Adrian Howard , Curtis "Ovid" Poe, , Mark Morgan . If you use this module, and can spare the time please let us know or rate it at . SEE ALSO Test::Class::Load Simple way to load "Test::Class" classes automatically. Test::Class::Most Test::Class with additional conveniences to reduce need for some boilerplate code. Also makes Test::Most testing functions available. Test::Class::Moose Testing framework allows you to write your tests in Moose and test Moose and non-Moose code. It offers reporting, extensibility, test inheritance, parallel testing and more. Delicious links on Test::Class. Perl Testing: A Developer's Notebook by Ian Langworth and chromatic Chapter 8 covers using Test::Class. Advanced Perl Programming, second edition by Simon Cozens Chapter 8 has a few pages on using Test::Class. The Perl Journal, April 2003 Includes the article "Test-Driven Development in Perl" by Piers Cawley that uses Test::Class. Test::Class Tutorial series written by Curtis "Ovid" Poe * * * * * Test::Builder Support module for building test libraries. Test::Simple & Test::More Basic utilities for writing tests. Overview of some of the many testing modules available on CPAN. Delicious links on perl testing. Test::Object Another approach to object oriented testing. Test::Group and Test::Block Alternatives to grouping sets of tests together. The following modules use Test::Class as part of their test suite. You might want to look at them for usage examples: App-GitGot, Aspect, Bricolage (), CHI, Cinnamon, Class::StorageFactory, CGI::Application::Search, DBIx::Romani, Xmldoom, Object::Relational, File::Random, Geography::JapanesePrefectures, Google::Adwords, Merge::HashRef, PerlBuildSystem, Ubic, Pixie, Yahoo::Marketing, and XUL-Node The following modules are not based on Test::Builder, but may be of interest as alternatives to Test::Class. Test::Unit Perl unit testing framework closely modeled on JUnit. Test::SimpleUnit A very simple unit testing framework. LICENCE Copyright 2002-2010 Adrian Howard, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Test-Class-0.50/lib/000700 000766 000024 00000000000 12534705543 014437 5ustar00etherstaff000000 000000 Test-Class-0.50/t/000700 000766 000024 00000000000 12534705543 014134 5ustar00etherstaff000000 000000 Test-Class-0.50/xt/000700 000766 000024 00000000000 12534705543 014324 5ustar00etherstaff000000 000000 Test-Class-0.50/xt/documented.t000755 000766 000024 00000000321 12432662765 016656 0ustar00etherstaff000000 000000 #! /usr/bin/perl -Tw use strict; use warnings; use Test::More; eval "use Test::Pod::Coverage 1.00"; plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage" if $@; all_pod_coverage_ok();Test-Class-0.50/xt/meta.t000644 000766 000024 00000001073 12432662765 015457 0ustar00etherstaff000000 000000 #!/usr/bin/perl # Test that our META.yml file matches the current specification. use strict; BEGIN { $| = 1; $^W = 1; } my $MODULE = 'Test::CPAN::Meta 0.12'; # Don't run tests for installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing module eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } meta_yaml_ok(); Test-Class-0.50/xt/perlcritic.t000644 000766 000024 00000000327 12432662765 016672 0ustar00etherstaff000000 000000 #! /usr/bin/perl -Tw use strict; use warnings; use Test::More; eval "use Test::Perl::Critic (-profile => 'xt/perlcriticrc')"; plan skip_all => "Test::Perl::Critic required for criticism" if $@; all_critic_ok(); Test-Class-0.50/xt/perlcriticrc000644 000766 000024 00000000000 12432662765 016741 0ustar00etherstaff000000 000000 Test-Class-0.50/xt/pmv.t000644 000766 000024 00000001247 12432662765 015336 0ustar00etherstaff000000 000000 #!/usr/bin/perl # Test that our declared minimum Perl version matches our syntax use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Perl::MinimumVersion 1.20', 'Test::MinimumVersion 0.008', ); # Don't run tests for installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_minimum_version_from_metayml_ok(); Test-Class-0.50/xt/pod.t000644 000766 000024 00000001167 12432662765 015317 0ustar00etherstaff000000 000000 #!/usr/bin/perl # Test that the syntax of our POD documentation is valid use strict; BEGIN { $| = 1; $^W = 1; } my @MODULES = ( 'Pod::Simple 3.07', 'Test::Pod 1.26', ); # Don't run tests for installs use Test::More; unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { plan( skip_all => "Author tests not required for installation" ); } # Load the testing modules foreach my $MODULE ( @MODULES ) { eval "use $MODULE"; if ( $@ ) { $ENV{RELEASE_TESTING} ? die( "Failed to load required release-testing module $MODULE" ) : plan( skip_all => "$MODULE not available for testing" ); } } all_pod_files_ok(); Test-Class-0.50/xt/spelling.t000644 000766 000024 00000002043 12432662765 016344 0ustar00etherstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Test::More; ## no critic my $spell_checker = eval q{ use Test::Spelling; use File::Which; which('ispell') || die 'no spell checker' }; ## use critic plan skip_all => 'Optional Test::Spelling, File::Which and aspell or ispell required to spellcheck POD' if $@; set_spell_cmd("$spell_checker -l"); add_stopwords( ); all_pod_files_spelling_ok(); __DATA__ AnnoCPAN CPAN perlmonks RSS LICENCE API APIs Bowden Bricolage Corion JUNIT JUnit Jansson Lindstrom ORGANISING STDOUT SUnit Startup TestCase TestRunner TestSuite Uenalan XSLT XUNIT al darwin organise refactored refactoring runtests scepticism startup teardown todo xUnit Aperghis Carnahan Cawley Deifik Hai Ishigaki Jochen Jore Jost Kenichi Kinyon Kirkup Krieger Lanning Mathieu Pham Sauve Stenzel Stosberg Tramoni ben et imacat qa Langworth Adrian BAILOUT Beck's Bjorn Cantrell Cozens Emil Ferrari Frankel Goddard Ian Johan Murat O'Neill Sebastien Smalltalk Terrence agianni co Curtis gnarly Dolan Brandt Hynek Edwardson Cosimo StrepponeTest-Class-0.50/t/00-load.t000644 000766 000024 00000000241 12432662765 015471 0ustar00etherstaff000000 000000 #!perl -T use Test::More tests => 1; BEGIN { use_ok( 'Test::Class::Load' ); } diag( "Testing Test::Class::Load $Test::Class::Load::VERSION, Perl $], $^X" ); Test-Class-0.50/t/20-load-classes.t000644 000766 000024 00000002776 12432662765 017145 0ustar00etherstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Test::More tests => 14; use Test::Class::Load 't/test-libs/lib1'; ok exists $INC{'Tests/Foo.pm'}, 'Classes in top level directories should be loaded'; ok exists $INC{'Tests/Foo/Bar.pm'}, '... as should tests in subdirectories'; is +Tests::Foo->foo, 'ooF::stseT', '... and the methods should work correctly'; is +Tests::Foo::Bar->foo, 'ooF::stseT', '... even if they are called from subclasses'; is +Tests::Foo::Bar->bar, 'raB::ooF::stseT', '... or they have their own methods'; delete $INC{'Tests/Foo.pm'}; delete $INC{'Tests/Foo/Bar.pm'}; delete $INC{'Test/Class/Load.pm'}; $SIG{__WARN__} = sub { warn @_ unless $_[0] =~ /^Subroutine \w+ redefined/; }; eval "use Test::Class::Load qw(t/test-libs/lib1 t/test-libs/lib2)"; ok !$@, 'Trying to load multiple lib paths should succeed'; ok exists $INC{'Tests/Foo.pm'}, 'Top level directories should be loaded even with multiple libs'; ok exists $INC{'Tests/Foo/Bar.pm'}, '... as should tests in subdirectories'; is +Tests::Foo->foo, 'ooF::stseT', '... and the methods should work correctly'; is +Tests::Foo::Bar->foo, 'ooF::stseT', '... even if they are called from subclasses'; is +Tests::Foo::Bar->bar, 'raB::ooF::stseT', '... or they have their own methods'; ok exists $INC{'MyTest/Baz.pm'}, 'And secondary libs should be loaded'; is +MyTest::Baz->baz, 23, '... and their methods should also work correctly'; eval "use Test::Class::Load qw( t/test-libs/fail )"; ok $@, "Trying to load a bad module fails";Test-Class-0.50/t/21-load-subclassed.t000644 000766 000024 00000001244 12432662765 017626 0ustar00etherstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Test::More tests => 7; use lib './t'; use TestClassLoadSubclass 't/test-libs/lib3'; ok exists $INC{'Tests/Good1.pm'}, 'Classes in top level directories should be loaded'; ok exists $INC{'Tests/Subdir/Good3.pm'}, '... as should classes in subdirectories'; ok !exists $INC{'Tests/Bad1.pm'}, 'Filtered out classes in top level directories should *not* be loaded'; ok !exists $INC{'Tests/Subdir/Bad2.pm'}, 'Filtered out classes in subdirectories should *not* be loaded'; for my $class (qw(Tests::Good1 Tests::Good2 Tests::Subdir::Good3)) { is $class->ok(), $class, 'Class ' . $class . ' method work as expected' } Test-Class-0.50/t/TestClassLoadSubclass.pm000644 000766 000024 00000000501 12432662765 020712 0ustar00etherstaff000000 000000 package TestClassLoadSubclass; use strict; use warnings; use base qw(Test::Class::Load); # Overriding this selects what test classes # are considered by T::C::Load sub is_test_class { my ($class, $file, $dir) = @_; # Get only "good" classes if ($file =~ m{Good}) { return 1; } return; } 1; Test-Class-0.50/t/Tests.t000644 000766 000024 00000000672 12432662765 015447 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::More tests => 2; { package My::Test; use base qw( Test::Class ); use Test::More; sub Tests_attribute_default_number_of_tests :Tests { my $self = shift; is( $self->num_tests, 'no_plan' ); } sub Tests_attribute_set_number_of_tests :Tests(1) { my $self = shift; is( $self->num_tests, 1 ); } } My::Test->runtests; Test-Class-0.50/t/_new.t000644 000766 000024 00000001052 12432662765 015266 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::Builder; use Test::More tests => 6; BEGIN { use_ok('Test::Class') || Test::Builder->BAILOUT("CANNOT USE Test::Class"); } package Foo; use base qw(Test::Class); package main; my $tc = Foo->new(foo => 42, bar=>3); isa_ok($tc, "Test::Class") || Test::Builder->BAILOUT("CANNOT CREATE Test::Class OBJECTS"); is($tc->{foo}, 42, 'key/value set'); my $tc2 = $tc->new(bar => 12); isa_ok($tc2, "Test::Class"); is($tc2->{foo}, 42, 'prototype key/value set'); is($tc2->{bar}, 12, 'new key/value set'); Test-Class-0.50/t/bad-autoloads.t000644 000766 000024 00000000775 12432662765 017070 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings FATAL => 'all'; use Test::More; BEGIN { no warnings; eval "use Contextual::Return"; if ($@ ) { plan skip_all => "need Contextual::Return" if $@; } else { plan tests => 2; use_ok 'Test::Class'; } } { our $is_warning_free = 1; $SIG{ __WARN__ } = sub { $is_warning_free = 0 }; Test::Class->_isa_class( 'Contextual::Return::Value' ); ok $is_warning_free, 'avoided warnings from Contextual::Return::Value'; } Test-Class-0.50/t/bailout.t000644 000766 000024 00000000456 12432662765 016004 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use base qw(Test::Class); use Test::Builder::Tester tests => 2; use Test::More; $ENV{TEST_VERBOSE}=0; test_out("Bail out! bailing out"); Test::Class->BAILOUT("bailing out"); END { test_test("bailout works"); is($?, 255, "exit value okay"); $?=0; } Test-Class-0.50/t/builder.t000644 000766 000024 00000000316 12432662765 015766 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Local::Test; use Test::More tests => 1; use Test::Builder; use base qw(Test::Class); is_deeply(Test::Builder->new, Test::Class->builder, "builder"); Test-Class-0.50/t/compile.t000755 000766 000024 00000000777 12432662765 016006 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use IO::File; use Fcntl; use base qw(Test::Class); use Test::More tests => 2; my $stderr; BEGIN { $stderr = IO::File->new_tmpfile or die "no tmp file ($!)\n"; *STDERR = $stderr; } my $sub = sub : Test(1) {print "ok\n"}; sub foo : Test(foo) {print "ok\n"} END { seek $stderr, SEEK_SET, 0; like(<$stderr>, qr/cannot test anonymous subs/, "cannot test anon sub"); is(<$stderr>, "bad test definition 'foo' in main->foo\n", "bad number detected"); } Test-Class-0.50/t/current_method.t000644 000766 000024 00000001073 12432662765 017363 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Local::Test; use Test::More tests => 4; use base qw(Test::Class); sub test : Test { my $self = shift; is($self->current_method, "test", "current_method in method"); } sub setup : Test(setup => 1) { my $self = shift; is($self->current_method, "test", "current_method in setup"); } sub teardown : Test(teardown => 1) { my $self = shift; is($self->current_method, "test", "current_method in teardown"); } __PACKAGE__->runtests; ok(!defined(__PACKAGE__->current_method), "current_test outside runtests"); Test-Class-0.50/t/diag_on_failure.t000644 000766 000024 00000001022 12432662765 017442 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::More tests => 1; use Test::Builder::Tester; $|=1; { package MyTestClass; use base qw( Test::Class ); use Test::More; sub passing_test : Test { pass } sub failing_test : Test { fail } } $ENV{TEST_VERBOSE}=0; test_out( "not ok 1 - failing test" ); test_fail( -5 ); test_err( "# (in MyTestClass->failing_test)" ); test_out( "ok 2 - passing test" ); Test::Class->runtests; test_test( "we show the test class and method name on test failure" ); Test-Class-0.50/t/die-in-setup.t000644 000766 000024 00000001301 12432662765 016636 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; { package Foo; use base qw( Test::Class ); use Test::More; sub setup_method :Test(setup) { die "oops - we died\n"; } sub test : Test { pass "this should never run"; } } use Test::Builder::Tester tests => 1; $ENV{TEST_VERBOSE}=0; test_out( "not ok 1 - setup_method (for test method 'test') died (oops - we died)" ); test_err( "# Failed test 'setup_method (for test method 'test') died (oops - we died)'" ); test_err( "# at $0 line 27." ); test_err( "# (in Foo->setup_method)" ); test_out("ok 2 # skip setup_method died"); Test::Class->runtests; test_test("die in setup caused test method to fail"); Test-Class-0.50/t/die_before_plan.t000644 000766 000024 00000001064 12432662765 017436 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test; use Test::Builder::Tester tests => 1; package Object::Test; use base 'Test::Class'; use Test::More; sub setup : Test(setup) { die "died before plan set\n"; } sub test : Test { ok(1==1, 'test just here to get setup method run'); } package main; $ENV{TEST_VERBOSE}=0; test_out("not ok 1 - setup (for test method 'test') died (died before plan set)"); test_fail(+3); test_err( "# (in Object::Test->setup)" ); test_out("ok 2 # skip setup died"); Object::Test->runtests; test_test("die before plan"); Test-Class-0.50/t/expected_tests.t000644 000766 000024 00000003127 12432662765 017366 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings FATAL => 'all'; package Tests1; use base qw(Test::Class); sub start : Test(setup => 1) {} sub test : Test(1) {} sub end : Test(teardown => 1) {} package Tests2; use base qw(Test::Class); sub start : Test(setup => no_plan) {} sub test : Test(1) {} sub end : Test(teardown => 1) {} package Tests3; use base qw(Test::Class); sub start : Test(setup => 1) {} sub test : Test(no_plan) {} sub end : Test(teardown => 1) {} package Tests4; use base qw(Test::Class); sub start : Test(setup => 1) {} sub test : Test(1) {} sub end : Test(teardown => no_plan) {} package Test5; use base qw(Test::Class); sub startup :Test( startup => no_plan ) {} sub test : Test(1) {} sub shutdown :Test( shutdown => 1 ) {} package Test6; use base qw(Test::Class); sub startup :Test( startup => 1 ) {} sub test : Test(1) {} sub shutdown :Test( shutdown => no_plan ) {} package main; use Test::More tests => 10; use Test::Exception; is(Tests1->expected_tests, 3, 'all set'); is(Tests2->expected_tests, 'no_plan', 'no_plan setup'); is(Tests3->expected_tests, 'no_plan', 'no_plan test'); is(Tests4->expected_tests, 'no_plan', 'no_plan teardown'); is(Test5->expected_tests, 'no_plan', 'no_plan startup' ); is(Test5->expected_tests, 'no_plan', 'no_plan shutdown' ); my $o1 = Tests1->new; my $o2 = Tests1->new; is(Test::Class->expected_tests($o1, $o2, 1), 7, 'expected_test_of'); is(Test::Class->expected_tests($o1, 'Tests3'), 'no_plan', 'no_plan expected_test_of'); dies_ok {Test::Class->expected_tests('foo')} 'bad test class'; dies_ok {Test::Class->expected_tests( undef )} 'undef test class'; Test-Class-0.50/t/fail1.t000644 000766 000024 00000000550 12432662765 015334 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use base qw(Test::Class); use Test::More tests => 2; use Test::Builder::Tester; $ENV{TEST_VERBOSE}=0; test_out("not ok 1 - failing"); test_out("not ok 2 - failing"); test_fail(+2); test_fail(+1); Test::Class->FAIL_ALL("failing"); END { test_test("FAIL_ALL with plan"); is($?, 2, "exit value okay"); $?=0; } Test-Class-0.50/t/fail2.t000644 000766 000024 00000001511 12534676162 015332 0ustar00etherstaff000000 000000 #!/usr/bin/perl -T use strict; use warnings; use Test::More tests => 2; use Test::Builder::Tester; package Object; sub new {return(undef)} package Object::Test; use base qw(Test::Class); use Test::More; sub _test_new : Test(3) { my $self = shift; isa_ok(Object->new, "Object") || $self->FAIL_ALL('cannot create Objects'); } package main; $ENV{TEST_VERBOSE}=0; my $identifier = ($Test::More::VERSION < 0.88) ? 'object' : 'thing'; test_out(qr/not ok 1 - (?:The $identifier|undef) isa '?Object'?\n/); test_out("not ok 2 - cannot create Objects"); test_fail(-12); test_err( "# (in Object::Test->_test_new)" ); test_err(qr/#\s+(?:The $identifier|undef) isn't defined\n/); test_fail(-15); test_err( "# (in Object::Test->_test_new)" ); Object::Test->runtests; END { test_test("fail2"); is($?, 2, "exit value okay"); $? = 0; } Test-Class-0.50/t/fail3.t000644 000766 000024 00000000571 12432662765 015341 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use base qw(Test::Class); use Test::More 'no_plan'; use Test::Builder::Tester; $ENV{TEST_VERBOSE}=0; test_out("ok 1 - passing"); pass("passing"); test_out("not ok 2 - failing"); test_fail(+1); Test::Class->FAIL_ALL("failing"); END { test_test("FAIL_ALL with no plan"); is($?, 1, "exit value okay"); print "1..2\n"; $?=0; } Test-Class-0.50/t/filter.t000644 000766 000024 00000000636 12432662765 015632 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; package Foo; use Test::More; use base qw(Test::Class); sub test_run : Test(1) { pass( "test_run not filtered, so is run" ); } package Bar; use Test::More; use base qw(Test::Class); sub test_filter_due_to_class : Test(1) { fail( "shouldn't run, due to class filter" ); } package main; Test::Class->add_filter( sub { $_[0] eq 'Foo' } ); Test::Class->runtests; Test-Class-0.50/t/filter_bad_filter.t000644 000766 000024 00000000350 12432662765 017776 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; package main; use Test::Class; use Test::More tests => 1; eval { Test::Class->add_filter( 'not a sub' ); }; like( $@, qr/^Filter isn't a code-ref/, "error on non-coderef filter" ); Test-Class-0.50/t/filter_fixtures.t000644 000766 000024 00000001514 12432662765 017557 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; package Foo; use Test::More; use base qw(Test::Class); sub test_filtered_startup : Test( startup => 1 ) { pass( "startup test is run, even though matches filter" ); } sub test_filtered_setup : Test( setup => 1 ) { pass( "setup test is run, even though matches filter" ); } sub test_filtered_teardown : Test( teardown => 1 ) { pass( "teardown test is run, even though matches filter" ); } sub test_filtered_shutdown : Test( shutdown => 1 ) { pass( "shutdown test is run, even though matches filter" ); } sub test_filtered : Test( 1 ) { fail( "shouldn't run, due to matching filter" ); } sub test_should_run : Test( 1 ) { pass( "should run, due to not matching filter" ); } package main; Test::Class->add_filter( sub { $_[1] !~ /filtered/ } ); Test::Class->runtests; Test-Class-0.50/t/filter_fixtures_only.t000644 000766 000024 00000001622 12534666222 020613 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::More tests => 1; { package Foo; use Test::More; use base qw(Test::Class); sub test_filtered_startup : Test( startup => 1 ) { fail( "startup test not run, as no normal tests are unfiltered" ); } sub test_filtered_setup : Test( setup => 1 ) { fail( "setup test not run, as no normal tests are unfiltered" ); } sub test_filtered_teardown : Test( teardown => 1 ) { fail( "teardown test not run, as no normal tests are unfiltered" ); } sub test_filtered_shutdown : Test( shutdown => 1 ) { fail( "shutdown test not run, as no normal tests are unfiltered" ); } sub test_filtered : Test( 1 ) { fail( "shouldn't run, due to matching filter" ); } } Test::Class->add_filter( sub { 0 } ); is( Test::Class->expected_tests, 0, 'setup/teardown not run when no test methods' ); Test-Class-0.50/t/filter_multiple.t000644 000766 000024 00000001401 12432662765 017534 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; package Foo; use Test::More; use base qw(Test::Class); sub test_not_filtered : Test(1) { pass( "test_not_filtered doesn't meet any filters, so is run" ); } sub test_filter_me : Test(1) { fail( "shouldn't run, due to filtering of /filter_me/" ); } sub test_me_too : Test(1) { fail( "shouldn't run, due to filtering of /me_too/" ); } sub test_filter_me_as_well : Test(1) { fail( "shouldn't run, due to filtering of /filter_me/" ); } sub test_another_not_matching : Test(1) { pass( "test_another_not_matching doesn't meet any filters, so is run" ); } package main; Test::Class->add_filter( sub { $_[1] !~ /filter_me/ } ); Test::Class->add_filter( sub { $_[1] !~ /me_too/ } ); Test::Class->runtests; Test-Class-0.50/t/header.t000644 000766 000024 00000000557 12432662765 015577 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::Builder::Tester; package Local::Test; use base qw(Test::Class); use Test::More; sub test : Test { pass("test in Test::Class"); } package main; use Test::More 'no_plan'; $ENV{TEST_VERBOSE}=0; test_out("ok 1 - test in Test::Class"); Local::Test->runtests; test_test("no duplicate headers"); print "1..1\n"; Test-Class-0.50/t/late_header.t000644 000766 000024 00000000622 12432662765 016575 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Local::Test; use base qw(Test::Class); use Test::More; sub setup : Test(setup) { my $self = shift; $self->num_method_tests('test', 2); } sub test : Test(no_plan) { my $self = shift; is($self->num_tests, 2, 'test number set'); is($self->builder->expected_tests, 2, 'builder expected tests set'); } package main; Local::Test->runtests(); Test-Class-0.50/t/methodinfo.t000644 000766 000024 00000001331 12432662765 016472 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::More 'no_plan'; use constant CLASS => 'Test::Class::MethodInfo'; BEGIN { use_ok( CLASS) } { isa_ok my $o = CLASS->new(name=> 'foo'), CLASS; ok $o->is_type('test'), 'method type is test by default'; is $o->num_tests, 1, 'test methods default to 1 test'; } __END__ { isa_ok my $o = CLASS->new(name=> 'foo', num_tests => 0), CLASS; is $o->num_tests, 0, 'test method can have zero tests'; } { foreach my $type qw(setup teardown startup shutdown) { isa_ok my $o = CLASS->new(name=> 'foo', type=> $type), CLASS, $type; ok $o->is_type($type), "method type is $type"; is $o->num_tests, 0, "$type methods default to 0 test"; } } Test-Class-0.50/t/named_test.t000644 000766 000024 00000000563 12432662765 016467 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::Builder::Tester; package Local::Test; use base qw(Test::Class); use Test::More; sub default_name : Test( 1 ) { pass(); } package main; use Test::More 'no_plan'; $ENV{TEST_VERBOSE}=0; test_out("ok 1 - default name"); Local::Test->runtests; test_test("test names set to method name by default"); print "1..1\n"; Test-Class-0.50/t/num_method_tests.t000644 000766 000024 00000003313 12432662765 017721 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Foo; use base qw(Test::Class); use Test::More; use Test::Exception; sub passN { my ($self, $n) = @_; my $m = $self->current_method; pass("$m just passing $_") foreach (1..$n); } sub new { my $class = shift; my $self = $class->SUPER::new(@_); is($self->num_method_tests('two_tests'), 2, 'fixed num tests'); is($self->num_method_tests('no_plan_test'), 'no_plan', 'no_plan tests'); throws_ok {$self->num_method_tests('fribble')} qr/not a test method/, 'cannot use non-method'; throws_ok {$self->num_method_tests('no_plan_test', 'goobah')} qr/not valid number/, 'cannot update illegal value'; lives_ok {$self->num_method_tests('no_plan_test', 2)} 'updated legal value'; is($self->num_method_tests('no_plan_test'), 2, 'update worked'); lives_ok {$self->num_method_tests('no_plan_test2', '+2')} 'updated extended'; is($self->num_method_tests('no_plan_test2'), '+2', 'update worked'); return($self); } sub two_tests : Test(2) {$_[0]->passN(2)} sub no_plan_test : Test(no_plan) {$_[0]->passN(2)} sub no_plan_test2 : Test(no_plan) {$_[0]->passN(2)} package Bar; use base qw(Foo); use Test::More; sub no_plan_test : Test(+1) {pass("just passing"); $_[0]->SUPER::no_plan_test} sub new { my $class = shift; my $self = $class->SUPER::new(@_); is($self->num_method_tests('no_plan_test'), '+1', 'extended method okay'); return($self); } package main; use Test::More tests => 19; use Test::Exception; my $tc = Bar->new; is(Bar->expected_tests, 'no_plan', 'class expected_tests'); is($tc->expected_tests, 7, 'object expected_tests'); throws_ok {$tc->num_method_tests('two_tests')} qr/not called in a Test::Class/, 'num_method_tests dies outside test class'; $tc->runtests; Test-Class-0.50/t/num_tests.t000755 000766 000024 00000000567 12432662765 016374 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Foo; use Test::More; use base qw(Test::Class); sub test_num_tests : Test(no_plan) { my $self = shift; is($self->num_tests, 'no_plan', "num_tests access okay"); $self->num_tests(2); is($self->num_tests, 2, "num_tests set okay"); } package main; use Test::More tests => 4; Foo->new->runtests; Foo->new->runtests; Test-Class-0.50/t/override.t000644 000766 000024 00000001006 12534672773 016157 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::More tests => 1; my $warning; BEGIN { $SIG{ __WARN__ } = sub { $warning = "@_" }; { package Base::Test; use base qw( Test::Class ); } { package Broken::Test; use base qw( Base::Test ); sub new : Test { "oops - we've overridden a public method with a test method"; } } } like $warning, qr/overriding public method/, 'cannot override a public method with a test method'; Test-Class-0.50/t/rt15870.t000644 000766 000024 00000000565 12432662765 015400 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::Exception tests => 1; { package SomeClassThatDefinesNew; sub new { return bless {}, shift } } { package TestClassWithBrokenMI; use base qw( SomeClassThatDefinesNew Test::Class ); } throws_ok { Test::Class->runtests } qr/Test::Class internals seem confused/, 'sensible error if new() is overridden'; Test-Class-0.50/t/rt17264.t000644 000766 000024 00000000376 12534672773 015402 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::Exception tests => 1; use lib 't/rt17264'; require 'Test/Class.pm'; throws_ok { Test::Class->runtests } qr/Test::Class was loaded too late/, 'we figured out that we loaded Test::Class too late';Test-Class-0.50/t/run_all_tests.t000644 000766 000024 00000001427 12432662765 017222 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::Class; my @CALLED = (); { package Base::Test; use base qw(Test::Class); Base::Test->SKIP_CLASS( 1 ); sub setup : Test { die "this should not run" } } { package A::Test; use base qw(Base::Test); use Test::More; sub setup : Test { pass 'non skipping test class run as expected'; push @CALLED, 'A::Test' } } package main; use Test::More tests => 5; ok(! Test::Class->SKIP_CLASS, 'Test::Class->SKIP_CLASS default' ); ok( Base::Test->SKIP_CLASS, 'Base::Test->SKIP_CLASS overridden' ); ok(! A::Test->SKIP_CLASS, 'A::Test->SKIP_CLASS default' ); Base::Test->runtests; is_deeply( [sort @CALLED], [ qw(A::Test) ], 'runtests skipped classes with SKIP_CLASS set' ); Test-Class-0.50/t/runtests.t000644 000766 000024 00000003261 12432662765 016231 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Foo; use base qw(Test::Class); use Test::More; sub initialise1 :Test(setup) { my $self = shift; ++$self->{initialise1}; } sub initialise2 :Test(setup => 1) { my $self = shift; ++$self->{initialise2}; is($self->{initialise1}, $self->{initialise2}, "initialise2: methods ran in order"); } sub test1 :Test(4) { my $self = shift; $self->{test}++; is($self->{initialise1}, 1, 'test1: initialise1 ran once'); is($self->{initialise2}, 1, 'test1: initialise2 ran once'); is($self->{test}, 1, 'test1: first test running'); is($self->{teardown1}, undef, 'test1: teardown not run'); } sub test2 : Test { fail("this failing tests should be overridden"); } sub teardown1 :Test(teardown => 1) { my $self = shift; my $m = $self->current_method; is($self->{test}, $self->{initialise1}, "teardown1: setup run for every test"); } package Bar; use base qw(Foo); use Test::More; sub test2 :Test(4) { my $self = shift; $self->{test}++; is($self->{initialise1}, 2, 'test2: initialise1 ran twice'); is($self->{initialise2}, 2, 'test2: initialise2 ran twice'); is($self->{test}, 2, 'test2: second test running'); is($self->{teardown1}, 1, 'test2: teardown ran once'); } sub teardown1 :Test(teardown => +3) { my $self = shift; my $m = $self->current_method; ++$self->{teardown1}; is($self->{test}, $self->{teardown1}, "teardown1: teardown run for every test"); is($self->{initialise1}, $self->{teardown1}, "teardown1: teardown run for every initialise1"); is($self->{initialise2}, $self->{teardown1}, "teardown1: teardown run for every initialise2"); $self->SUPER::teardown1; } package main; use Test::More tests => 18; Bar->new->runtests; Test-Class-0.50/t/runtests_die.t000755 000766 000024 00000001641 12534676162 017054 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Object; sub new { undef } package Foo; use Test::More; use base qw(Test::Class); sub test_object : Test(2) { my $object = Object->new; isa_ok($object, "Object") or die("could not create object\n"); is($object->open, "open worked"); } package main; use Test::Builder::Tester tests => 1; $ENV{TEST_VERBOSE}=0; my $filename = sub { return (caller)[1] }->(); my $identifier = ($Test::More::VERSION < 0.88) ? 'object' : 'thing'; test_out( qr/not ok 1 - (?:The $identifier|undef) isa '?Object'?\n/); test_err( "# Failed test ($filename at line 15)"); test_err( "# (in Foo->test_object)" ); test_err( qr/# (?:The $identifier|undef) isn't defined\n/); test_out( "not ok 2 - test_object died (could not create object)"); test_err( "# Failed test ($filename at line 33)"); test_err( "# (in Foo->test_object)" ); Foo->runtests; test_test("early die handled"); Test-Class-0.50/t/runtests_die_empty.t000644 000766 000024 00000001623 12432662765 020270 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Object; use overload bool => sub { 1 }, # there is an exception here even if it stringifies as empty! '""' => 'as_string', fallback => 1; sub new { my ($class, %args) = @_; bless { %args }, $class; } sub as_string { return defined $_[0]->{message} ? $_[0]->{message} : ''; } package Foo; use Test::More; use base qw(Test::Class); sub die_empty : Test(1) { die Object->new(); fail 'we should never get here'; } package main; use Test::Builder::Tester tests => 1; $ENV{TEST_VERBOSE}=0; my $filename = sub { return (caller)[1] }->(); test_out( "not ok 1 - die_empty died ()"); test_err( "# Failed test 'die_empty died ()'" ); test_err( "# at $filename line 40."); test_err( "# (in Foo->die_empty)" ); Foo->runtests; test_test("we can handle an exception that stringifies to the empty string"); Test-Class-0.50/t/runtests_die_nearlyempty.t000644 000766 000024 00000001543 12432662765 021504 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Foo; use Test::More; use base qw(Test::Class); sub die_one_cr : Test(1) { die "\n"; fail 'we should never get here'; } sub die_two_cr : Test(1) { die "\n\n"; fail 'we should never get here'; } package main; use Test::Builder::Tester tests => 1; $ENV{TEST_VERBOSE}=0; my $filename = sub { return (caller)[1] }->(); test_out( "not ok 1 - die_one_cr died ()"); test_err( "# Failed test 'die_one_cr died ()'" ); test_err( "# at $filename line 36."); test_err( "# (in Foo->die_one_cr)" ); test_out( "not ok 2 - die_two_cr died ("); test_out( "# )"); test_err( "# Failed test 'die_two_cr died (" ); test_err( "# )'"); test_err( "# at $filename line 36."); test_err( "# (in Foo->die_two_cr)" ); Foo->runtests; test_test("early die with nearly-empty messages handled"); Test-Class-0.50/t/runtests_extra.t000755 000766 000024 00000000665 12432662765 017444 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; $ENV{TEST_VERBOSE}=0; package Foo; use Test::More; use base qw(Test::Class); sub extra_test : Test(1) { ok(1, "expected test"); ok(1, "extra test"); } package main; use Test::Builder::Tester tests => 1; test_out("ok 1 - expected test"); test_out("ok 2 - extra test"); test_err("# expected 1 test(s) in Foo::extra_test, 2 completed"); Foo->runtests; test_test("extra test detected"); Test-Class-0.50/t/runtests_noplan.t000755 000766 000024 00000001053 12432662765 017600 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Foo; use Test::More; use base qw(Test::Class); sub set_tests : Test(1) { pass("this should pass"); } sub undef_tests : Test(no_plan) { my $self = shift; my $n = $self->{runtime_tests}; foreach $n (1..$n) { pass("runtime test $n"); } } package main; use Test::More; use Test::Exception; my $foo = Foo->new; $foo->{runtime_tests} = 2; $foo->runtests; my $expected = $foo->{runtime_tests} + 1; my $ran = $foo->builder->current_test; is($ran, $expected, "expected number of tests ran"); Test-Class-0.50/t/runtests_of.t000644 000766 000024 00000001001 12432662765 016703 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Tests1; use base qw(Test::Class); use Test::More; sub setup : Test(setup) { my $self = shift; $self->FAIL_ALL("premature plan") if $self->builder->expected_tests; } sub test : Test { pass('Tests1 test') } package Tests2; use base qw(Test::Class); use Test::More; sub test : Test { pass('Tests2 test') } package main; use Test::More; Test::Class->runtests('Tests1', 'Tests2', +1); is(Tests1->builder->expected_tests, 3, 'correct number of tests'); Test-Class-0.50/t/runtests_result.t000644 000766 000024 00000001376 12432662765 017634 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Fail; use Test::More; use base qw(Test::Class); sub test1 : Test(1) { fail("fails"); } sub test2 : Test(1) { pass("passes"); } package Pass; use Test::More; use base qw(Test::Class); sub test1 : Test(1) { pass("a successful test"); } package main; use Test::Builder::Tester tests => 4; use Test::More; $ENV{TEST_VERBOSE}=0; my $all_ok; my $filename = sub { return (caller)[1] }->(); test_out( "not ok 1 - fails" ); test_err( "# Failed test ($filename at line 11)" ); test_err( "# (in Fail->test1)" ); test_out("ok 2 - passes"); $all_ok = Fail->runtests; test_test("single failure ran okay"); is($all_ok, 0, "failure detected"); $all_ok = Pass->runtests; ok($all_ok, "success detected"); Test-Class-0.50/t/runtests_return.t000755 000766 000024 00000001762 12432662765 017637 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; $ENV{TEST_VERBOSE}=0; package Foo; use Test::More; use base qw(Test::Class); sub darwin_only : Tests(2) { return("darwin only test");# unless $^O eq "darwin"; ok(-w "/Library", "/Library writable"); ok(-r "/Library", "/Library readable"); } package Bar; use Test::More; use base qw(Test::Class); sub fail_if_returned_early { 1 } sub darwin_only : Tests(2) { return("darwin only test");# unless $^O eq "darwin"; ok(-r "/Library", "/Library readable"); ok(-w "/Library", "/Library writable"); } package main; use Test::Builder::Tester tests => 2; test_out("ok 1 # skip darwin only test"); test_out("ok 2 # skip darwin only test"); Foo->runtests; test_test("early return handled (skip)"); test_out("not ok 1 - (Bar::darwin_only returned before plan complete)"); test_out("not ok 2 - (Bar::darwin_only returned before plan complete)"); test_err(qr/.*in Bar->darwin_only.*/s); Bar->runtests; test_test("early return handled (fail)"); Test-Class-0.50/t/runtests_trailing.t000755 000766 000024 00000000726 12432662765 020130 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Foo; use Test::More; use base qw(Test::Class); sub trailing_exception : Test(1) { pass("successful test"); die "died\n"; } package main; use Test::Builder::Tester tests => 1; $ENV{TEST_VERBOSE}=0; test_out("ok 1 - successful test"); test_out("not ok 2 - trailing_exception died (died)"); test_fail(+2); test_err( "# (in Foo->trailing_exception)" ); Foo->runtests; test_test("trailing expection detected"); Test-Class-0.50/t/runtests_with_wrong_class.t000644 000766 000024 00000000423 12432662765 021662 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings FATAL => 'all'; use Test::Exception; use Test::More tests => 2; BEGIN { use_ok 'Test::Class' } dies_ok { Test::Class->runtests( 'Not::A::Test::Class' ) } 'runtests dies if we are given something that is not a test class'; Test-Class-0.50/t/show_plan_in_shutdown.t000644 000766 000024 00000000661 12534666222 020751 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings FATAL => 'all'; use Test::More; my $shutdown_has_run; { package My::Test; use base qw( Test::Class ); use Test::More; sub shutdown :Test( shutdown ) { $shutdown_has_run = 1; } sub test : Test { pass "passing test to force shutdown method to run"; } } My::Test->runtests( +1 ); ok $shutdown_has_run, "shutdown method has run"; Test-Class-0.50/t/skip1.t000644 000766 000024 00000001070 12432662765 015365 0ustar00etherstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use base qw(Test::Class); use Test::More; use Test::Builder; use Fcntl; use IO::File; my $io = IO::File->new_tmpfile or die "couldn't create tmp file ($!)\n"; my $Test = Test::Builder->new; $Test->output($io); $Test->failure_output($io); Test::Class->SKIP_ALL("skipping"); END { seek $io, SEEK_SET, 0; print "1..1\n"; my @output = <$io>; shift @output if $output[0] =~ /^TAP version \d+/; my $ok = $output[0] =~ /^1..0 # Skip skipping$/i; print "not " unless $ok; print "ok 1 - SKIP_ALL called skip_all\n"; } Test-Class-0.50/t/skip2.t000644 000766 000024 00000002305 12432662765 015370 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; # Override exit before Test::Class is loaded so the real override # will be seen later. BEGIN { *CORE::GLOBAL::exit = sub (;$) { return @_ ? CORE::exit($_[0]) : CORE::exit(); }; } package Local::Test; use base qw(Test::Class); use Test::Builder::Tester tests => 4; use Test::More; sub _only : Test(setup => 1) { my $self = shift; $self->builder->ok(1==1); $self->SKIP_ALL("skippy"); } sub test : Test(3) { die "this should never run!"; } test_out("ok 1 - test"); test_out("ok 2 # skip skippy"); test_out("ok 3 # skip skippy"); test_out("ok 4 # skip skippy"); { # Capture the exit from SKIP_ALL, do the tests on the TAP output, # and then exit for real to stop Test::Class from continuing. no warnings 'redefine'; local *CORE::GLOBAL::exit = sub { test_test("SKIP_ALL"); my $exit_status = @_ ? shift : 0; is $exit_status, 0, "exit ok"; # Due to a quirk in Test::Builder::Tester, we're stuck with the # plan generated by Test::Class (4 tests) pass("make the plan happy"); pass("make the plan happy"); CORE::exit($exit_status); }; Local::Test->runtests; } Test-Class-0.50/t/skip_class_reason.t000755 000766 000024 00000002122 12432662765 020042 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::Class; use Test; use Fcntl; use IO::File; use Test::Builder; { package Foo::Test; use base qw(Test::Class); use Test::More; sub skipped_with_reason : Test( 3 ) { fail( "this should not run" ) } __PACKAGE__->SKIP_CLASS( 'because SKIP_CLASS returned a string' ); } { package Bar::Test; use base qw(Test::Class); use Test::More; sub skipped_with_reason : Test( 3 ) { fail( "this should not run" ) } __PACKAGE__->SKIP_CLASS( 1 ); } plan tests => 3; my $io = IO::File->new_tmpfile or die "couldn't create tmp file ($!)\n"; my $Test = Test::Builder->new; $Test->output($io); $Test->failure_output($io); $ENV{TEST_VERBOSE}=0; Test::Class->runtests; END { seek $io, SEEK_SET, 0; while (my $actual = <$io>) { chomp($actual); next if $actual =~ /^TAP version \d+/; $actual =~ s{# skip\b}{# skip}i; # normalize directives my $expected=; chomp($expected); ok($actual, $expected); } ok($?, 0, "exit value okay"); $?=0; } __DATA__ 1..1 ok 1 # skip because SKIP_CLASS returned a string Test-Class-0.50/t/skip_empty_classes.t000644 000766 000024 00000002316 12432662765 020243 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::Class; use Test; use Fcntl; use IO::File; use Test::Builder; { package Base::Test; use base qw(Test::Class); use Test::More; sub startup :Test(startup => 1) { pass "startup run" } sub setup :Test(setup => 1) { pass "setup run" } sub teardown :Test(teardown => 1) { pass "teardown run" } sub shutdown :Test(shutdown => 1) { pass "shutdown run" } } { package Bar::Test; use base qw(Base::Test); use Test::More; sub the_test :Test { pass "the_test has been run"; } } # plan tests => 3; # # my $io = IO::File->new_tmpfile or die "couldn't create tmp file ($!)\n"; # my $Test = Test::Builder->new; # $Test->output($io); # $Test->failure_output($io); # # $ENV{TEST_VERBOSE}=0; $ENV{TEST_VERBOSE}=1; Test::Class->runtests; # # END { # seek $io, SEEK_SET, 0; # while (my $actual = <$io>) { # chomp($actual); # my $expected=; chomp($expected); # ok($actual, $expected); # } # # ok($?, 0, "exit value okay"); # $?=0; # } # # __DATA__ # 1..1 # ok 1 # skip because SKIP_CLASS returned a string Test-Class-0.50/t/spaces.t000644 000766 000024 00000000552 12432662765 015620 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::Builder::Tester; package Local::Test; use base qw(Test::Class); use Test::More; sub test : Test( 1 ) { pass("it works"); } package main; use Test::More 'no_plan'; $ENV{TEST_VERBOSE}=0; test_out("ok 1 - it works"); Local::Test->runtests; test_test("can have spaces around attributes"); print "1..1\n"; Test-Class-0.50/t/startup.t000644 000766 000024 00000001621 12432662765 016042 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; my @ORDER = qw ( start1 start2 setup1 setup2 test1 tear1 tear2 setup1 setup2 test2 tear1 tear2 end1 end2 ); package Foo::Test; use base qw(Test::Class); use Test::More; sub trace_ok { my $caller = (caller(1))[3]; $caller =~ s/^.*://s; my $expected = shift @ORDER; is($caller, $expected, "called $expected"); } sub start1 : Test(startup=>1) { trace_ok() } sub start2 : Test(startup=>1) { trace_ok() } sub setup1 : Test(setup=>1) { trace_ok() } sub setup2 : Test(setup=>1) { trace_ok() } sub test1 : Test(1) { trace_ok() } sub test2 : Test(1) { trace_ok() } sub tear1 : Test(teardown=>1) { trace_ok() } sub tear2 : Test(teardown=>1) { trace_ok() } sub end1 : Test(shutdown=>1) { trace_ok() } sub end2 : Test(shutdown=>1) { trace_ok() } package main; use Test::More; Foo::Test->runtests(+1); ok(@ORDER==0, 'all expected methods ran'); Test-Class-0.50/t/startup_that_dies.t000644 000766 000024 00000001077 12432662765 020073 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; { package StartMethodThatDies; use base qw(Test::Class); use Test::More; sub startup_that_dies : Test( startup ) { die "oops!\n" } sub my_test_method : Tests { fail('should be skipped because of the startup exception'); } } use Test::Builder::Tester tests => 1; test_out("not ok 1 - startup_that_dies died (oops!)"); test_fail( +2 ); test_err( "# (in StartMethodThatDies->startup_that_dies)" ); Test::Class->runtests; test_test("exception in startup method causes all tests to be skipped"); Test-Class-0.50/t/teardown-when-test-dies.t000644 000766 000024 00000001326 12432662765 021023 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; my $line; { package TeardownWhenTestDies; use base qw(Test::Class); use Test::More; sub setup_that_runs : Test( setup => 1 ) { ok(1, "setup works"); } sub my_test_method : Tests { BEGIN { $line = __LINE__ } die "oops!"; } sub teardown_that_runs : Test( teardown => 1 ) { ok(1, 'teardown is run'); } } use Test::Builder::Tester tests => 1; test_out("ok 1 - setup works\nnot ok 2 - my_test_method died (oops! at ${\ __FILE__ } line $line.)\nok 3 - teardown is run"); test_fail( +2 ); test_err( "# (in TeardownWhenTestDies->my_test_method)" ); Test::Class->runtests; test_test("exception in method, but teardown is still run"); Test-Class-0.50/t/test-libs/000700 000766 000024 00000000000 12534705543 016042 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test_classes.t000644 000766 000024 00000000660 12432662765 017036 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; use Test::More tests => 1; use Test::Exception; use Test::Class; lives_and { # Devel::Symdump::packages returns 0 in the list of packages on some # platforms. Don't yet understand why. no warnings; local *Devel::Symdump::packages = sub { 0, 'Test::Class' }; is_deeply( [Test::Class->_test_classes], [ 'Test::Class' ] ); } '_test_classes deals with undef values'; Test-Class-0.50/t/test_deep.t000644 000766 000024 00000000432 12432662765 016313 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::More tests => 1; use Test::Class; { package Test::Deep; sub isa { 1 } } is_deeply [ Test::Class->_test_classes ], [ 'Test::Class' ], 'Test::Deep is not included as a test class, even though isa always returns true'; Test-Class-0.50/t/test_method.t000644 000766 000024 00000002766 12432662765 016672 0ustar00etherstaff000000 000000 #! /usr/bin/perl use strict; use warnings; use Test::More tests => 4; use Test::Exception; use Test::Builder::Tester; { package MyTestClass; use base qw(Test::Class); use Test::More; sub startup : Test( startup => 1 ) { pass "startup" } sub shutdown : Test( shutdown => 1 ) { pass "shutdown" } sub setup : Test( setup => 1 ) { pass "setup" } sub teardown : Test( teardown => 1 ) { pass "teardown" } sub test1 : Test { pass "test1" } sub test2 : Test { pass "test2" } sub test3 : Test { pass "test3" } } $ENV{ TEST_VERBOSE } = 0; $ENV{ TEST_METHOD } = '+++'; throws_ok { MyTestClass->runtests } qr/\A\QTEST_METHOD (+++) is not a valid regexp/, '$ENV{TEST_METHOD} with an invalid regex should die'; delete $ENV{ TEST_METHOD }; expecting_tests( qw( startup setup test1 teardown setup test2 teardown setup test3 teardown shutdown ) ); test_test( "no TEST_METHOD runs all tests" ); $ENV{ TEST_METHOD } = 'test1'; expecting_tests( qw( startup setup test1 teardown shutdown ) ); test_test( "single match just runs one test" ); $ENV{ TEST_METHOD } = 'test[13]'; expecting_tests( qw( startup setup test1 teardown setup test3 teardown shutdown ) ); test_test( "two matches run both tests" ); #### sub expecting_tests { my @test_descriptions = @_; my $n = 1; foreach my $description ( @test_descriptions ) { test_out( "ok " . $n++ . " - $description" ); } MyTestClass->runtests; } Test-Class-0.50/t/test_verbose.t000644 000766 000024 00000000722 12432662765 017045 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Local::Test; use base qw(Test::Class); use Test::More; sub test1 : Test { ok(1) } sub test2 : Test { ok(1) } package main; use Test::Builder::Tester tests => 1; $ENV{TEST_VERBOSE}=1; test_diag(""); test_diag("Local::Test->test1"); test_out("ok 1 - test1"); test_diag(""); test_diag("Local::Test->test2"); test_out("ok 2 - test2"); Local::Test->runtests; test_test("TEST_VERBOSE outputs method diagnostic"); Test-Class-0.50/t/todo.t000755 000766 000024 00000002431 12432662765 015310 0ustar00etherstaff000000 000000 #! /usr/bin/perl -T use strict; use warnings; package Object; sub live {undef} package Foo; use Test::More; use base qw(Test::Class); sub todo_test : Test { local $TODO = "unimplemented"; ok(Object->live, "object live"); } package main; use Test::Builder::Tester tests => 2; use Test::More; $ENV{TEST_VERBOSE}=0; my $filename = sub { return (caller)[1] }->(); my $test_more_version = eval($Test::More::VERSION); diag "Test::More: $test_more_version"; test_out( "not ok 1 - object live # TODO unimplemented" ); if ($test_more_version >= 0.9501) { # Test-Simple-0.95_01 or later output TODO message to output handle. # see http://cpansearch.perl.org/src/MSCHWERN/Test-Simple-0.95_01/Changes # Test::Builder::Tester now sets $tb->todo_output to the output handle and # not the error handle (to be in accordance with the default behaviour of # Test::Builder and allow for testing TODO test behaviour). test_out( "# Failed (TODO) test ($filename at line 16)" ); test_out( "# (in Foo->todo_test)" ); } else { test_err( "# Failed (TODO) test ($filename at line 16)" ); test_err( "# (in Foo->todo_test)" ); } Foo->runtests; test_test("todo tests work"); package Foo; is( Foo->num_method_tests('todo_test'), 1, 'todo_test should run 1 test' ); Test-Class-0.50/t/test-libs/fail/000700 000766 000024 00000000000 12534705543 016755 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib1/000700 000766 000024 00000000000 12534705543 016671 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib2/000700 000766 000024 00000000000 12534705543 016672 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib3/000700 000766 000024 00000000000 12534705543 016673 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib3/Tests/000700 000766 000024 00000000000 12534705543 017775 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib3/Tests/Bad1.pm000644 000766 000024 00000000114 12432662765 021115 0ustar00etherstaff000000 000000 package Tests::Bad1; use strict; use warnings; sub ok { __PACKAGE__ } 1; Test-Class-0.50/t/test-libs/lib3/Tests/Good1.pm000644 000766 000024 00000000116 12432662765 021321 0ustar00etherstaff000000 000000 package Tests::Good1; use strict; use warnings; sub ok { __PACKAGE__ } 1; Test-Class-0.50/t/test-libs/lib3/Tests/Good2.pm000644 000766 000024 00000000115 12432662765 021321 0ustar00etherstaff000000 000000 package Tests::Good2; use strict; use warnings; sub ok { __PACKAGE__ } 1; Test-Class-0.50/t/test-libs/lib3/Tests/Subdir/000700 000766 000024 00000000000 12534705543 021225 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib3/Tests/Subdir/Bad2.pm000644 000766 000024 00000000124 12432662765 022347 0ustar00etherstaff000000 000000 package Tests::Subdir::Bad2; use strict; use warnings; sub ok { __PACKAGE__ } 1; Test-Class-0.50/t/test-libs/lib3/Tests/Subdir/Good3.pm000644 000766 000024 00000000126 12432662765 022554 0ustar00etherstaff000000 000000 package Tests::Subdir::Good3; use strict; use warnings; sub ok { __PACKAGE__ } 1; Test-Class-0.50/t/test-libs/lib2/MyTest/000700 000766 000024 00000000000 12534705543 020117 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib2/MyTest/Baz.pm000644 000766 000024 00000000104 12432662765 021203 0ustar00etherstaff000000 000000 package MyTest::Baz; use strict; use warnings; sub baz { 23 } 1; Test-Class-0.50/t/test-libs/lib1/Tests/000700 000766 000024 00000000000 12534705543 017773 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib1/Tests/Foo/000700 000766 000024 00000000000 12534705543 020516 5ustar00etherstaff000000 000000 Test-Class-0.50/t/test-libs/lib1/Tests/Foo.pm000644 000766 000024 00000000134 12432662765 021071 0ustar00etherstaff000000 000000 package Tests::Foo; use strict; use warnings; sub foo { scalar reverse __PACKAGE__ } 1; Test-Class-0.50/t/test-libs/lib1/Tests/Foo/Bar.pm000644 000766 000024 00000000171 12432662765 021576 0ustar00etherstaff000000 000000 package Tests::Foo::Bar; use strict; use warnings; use base 'Tests::Foo'; sub bar { scalar reverse __PACKAGE__ } 1; Test-Class-0.50/t/test-libs/fail/MyFail.pm000644 000766 000024 00000000053 12432662765 020511 0ustar00etherstaff000000 000000 #! /usr/bin/perl 0; # we deliberately failTest-Class-0.50/lib/Test/000700 000766 000024 00000000000 12534705543 015356 5ustar00etherstaff000000 000000 Test-Class-0.50/lib/Test/Class/000700 000766 000024 00000000000 12534705543 016423 5ustar00etherstaff000000 000000 Test-Class-0.50/lib/Test/Class.pm000644 000766 000024 00000174147 12534676162 017015 0ustar00etherstaff000000 000000 use strict; use warnings; use 5.006; package Test::Class; use Attribute::Handlers; use Carp; use MRO::Compat; use Storable qw(dclone); use Test::Builder; use Test::Class::MethodInfo; use Try::Tiny; our $VERSION = '0.50'; my $Check_block_has_run; { no warnings 'void'; CHECK { $Check_block_has_run = 1 } } use constant NO_PLAN => "no_plan"; use constant SETUP => "setup"; use constant TEST => "test"; use constant TEARDOWN => "teardown"; use constant STARTUP => "startup"; use constant SHUTDOWN => "shutdown"; our $Current_method = undef; sub current_method { $Current_method } my $Builder = Test::Builder->new; sub builder { $Builder } my $Tests = {}; my @Filters = (); my %_Test; # inside-out object field indexed on $self sub DESTROY { my $self = shift; delete $_Test{ $self }; } sub _test_info { my $self = shift; return ref($self) ? $_Test{$self} : $Tests; } sub _method_info { my ($self, $class, $method) = @_; return( _test_info($self)->{$class}->{$method} ); } sub _methods_of_class { my ( $self, $class ) = @_; my $test_info = _test_info($self) or die "Test::Class internals seem confused. Did you override " . "new() in a sub-class or via multiple inheritance?\n"; return values %{ $test_info->{$class} }; } sub _parse_attribute_args { my $args = shift || ''; my $num_tests; my $type; $args =~ s/\s+//sg; foreach my $arg (split /=>/, $args) { if (Test::Class::MethodInfo->is_num_tests($arg)) { $num_tests = $arg; } elsif (Test::Class::MethodInfo->is_method_type($arg)) { $type = $arg; } else { die 'bad attribute args'; } } return( $type, $num_tests ); } sub _is_public_method { my ($class, $name) = @_; my @parents = @{mro::get_linear_isa($class)}; shift @parents; foreach my $parent_class ( @parents ) { return unless $parent_class->can( $name ); return if _method_info( $class, $parent_class, $name ); } return 1; } sub Test : ATTR(CODE,RAWDATA) { my ($class, $symbol, $code_ref, $attr, $args) = @_; if ($symbol eq "ANON") { warn "cannot test anonymous subs - you probably loaded a Test::Class too late (after the CHECK block was run). See 'A NOTE ON LOADING TEST CLASSES' in perldoc Test::Class for more details\n"; } else { my $name = *{$symbol}{NAME}; warn "overriding public method $name with a test method in $class\n" if _is_public_method( $class, $name ); eval { $class->add_testinfo($name, _parse_attribute_args($args)) } || warn "bad test definition '$args' in $class->$name\n"; } } sub Tests : ATTR(CODE,RAWDATA) { my ($class, $symbol, $code_ref, $attr, $args) = @_; $args ||= 'no_plan'; Test( $class, $symbol, $code_ref, $attr, $args ); } sub add_testinfo { my($class, $name, $type, $num_tests) = @_; $Tests->{$class}->{$name} = Test::Class::MethodInfo->new( name => $name, num_tests => $num_tests, type => $type, ); } sub _class_of { my $self = shift; return ref $self ? ref $self : $self; } sub new { my $proto = shift; my $class = _class_of( $proto ); $proto = {} unless ref($proto); my $self = bless {%$proto, @_}, $class; $_Test{$self} = dclone($Tests); return($self); } sub _get_methods { my ( $self, @types ) = @_; my $test_class = _class_of( $self ); my $test_method_regexp = $ENV{ TEST_METHOD } || '.*'; my $method_regexp = eval { qr/\A$test_method_regexp\z/ }; die "TEST_METHOD ($test_method_regexp) is not a valid regexp: $@" if $@; my %methods = (); foreach my $class ( @{mro::get_linear_isa( $test_class )} ) { FILTER: foreach my $info ( _methods_of_class( $self, $class ) ) { my $name = $info->name; if ( $info->type eq TEST ) { # determine if method is filtered, true if *any* filter # returns false. foreach my $filter ( @Filters ) { next FILTER unless $filter->( $class, $name ); } } foreach my $type ( @types ) { if ( $info->is_type( $type ) ) { $methods{ $name } = 1 unless $type eq TEST && $name !~ $method_regexp; } } } } my @methods = sort keys %methods; return @methods; } sub _num_expected_tests { my $self = shift; if (my $reason = $self->SKIP_CLASS ) { return $reason eq "1" ? 0 : 1; }; my @test_methods = _get_methods($self, TEST); return 0 unless @test_methods; my @startup_shutdown_methods = _get_methods($self, STARTUP, SHUTDOWN); my $num_startup_shutdown_methods = _total_num_tests($self, @startup_shutdown_methods); return(NO_PLAN) if $num_startup_shutdown_methods eq NO_PLAN; my @fixture_methods = _get_methods($self, SETUP, TEARDOWN); my $num_fixture_tests = _total_num_tests($self, @fixture_methods); return(NO_PLAN) if $num_fixture_tests eq NO_PLAN; my $num_tests = _total_num_tests($self, @test_methods); return(NO_PLAN) if $num_tests eq NO_PLAN; return($num_startup_shutdown_methods + $num_tests + @test_methods * $num_fixture_tests); } sub expected_tests { my $total = 0; foreach my $test (@_) { if ( _isa_class( __PACKAGE__, $test ) ) { my $n = _num_expected_tests($test); return NO_PLAN if $n eq NO_PLAN; $total += $n; } elsif ( defined $test && $test =~ m/^\d+$/ ) { $total += $test; } else { $test = 'undef' unless defined $test; croak "$test is not a Test::Class or an integer"; } } return $total; } sub _total_num_tests { my ($self, @methods) = @_; my $class = _class_of( $self ); my $total_num_tests = 0; foreach my $method (@methods) { foreach my $class (@{mro::get_linear_isa($class)}) { my $info = _method_info($self, $class, $method); next unless $info; my $num_tests = $info->num_tests; return(NO_PLAN) if ($num_tests eq NO_PLAN); $total_num_tests += $num_tests; last unless $num_tests =~ m/^\+/ } } return($total_num_tests); } sub _has_no_tests { my ( $self, $method ) = @_; return _total_num_tests( $self, $method ) eq '0'; } sub _all_ok_from { my ($self, $start_test) = @_; # The Test::Builder 1.5 way to do it if( $Builder->can("history") ) { return $Builder->history->can_succeed; } # The Test::Builder 0.x way to do it else { my $current_test = $Builder->current_test; return(1) if $start_test == $current_test; my @results = ($Builder->summary)[$start_test .. $current_test-1]; foreach my $result (@results) { return(0) unless $result } return(1); } } sub _exception_failure { my ($self, $method, $exception, $tests) = @_; local $Test::Builder::Level = 3; my $message = $method; $message .= " (for test method '$Current_method')" if defined $Current_method && $method ne $Current_method; _show_header($self, @$tests); chomp $exception; $Builder->ok(0, "$message died ($exception)"); _threw_exception( $self, $method => 1 ); } my %threw_exception; sub _threw_exception { my ( $self, $method, $optional_value) = @_; my $class = ref( $self ); $threw_exception{ $class }{ $method } = $optional_value if defined $optional_value; return $threw_exception{ $class }{ $method }; } sub _run_method { my ($self, $method, $tests) = @_; _threw_exception( $self, $method => 0 ); my $num_start = $Builder->current_test; my $skip_reason; my $original_ok = \&Test::Builder::ok; no warnings; local *Test::Builder::ok = sub { my ($builder, $test, $description) = @_; local $Test::Builder::Level = $Test::Builder::Level+1; unless ( defined($description) ) { $description = $self->current_method; $description =~ tr/_/ /; } my $is_ok = $original_ok->($builder, $test, $description); unless ( $is_ok ) { my $class = ref $self; $Builder->diag( " (in $class->$method)" ); } return $is_ok; }; my $exception; $skip_reason = try { $self->$method } catch { $exception = $_; undef }; $skip_reason = $method unless $skip_reason; my $num_done = $Builder->current_test - $num_start; my $num_expected = _total_num_tests($self, $method); $num_expected = $num_done if $num_expected eq NO_PLAN; if ($num_done == $num_expected) { _exception_failure($self, $method, $exception, $tests) if $exception; } elsif ($num_done > $num_expected) { my $class = ref $self; $Builder->diag("expected $num_expected test(s) in $class\::$method, $num_done completed\n"); } else { until (($Builder->current_test - $num_start) >= $num_expected) { if ($exception) { _exception_failure($self, $method, $exception, $tests); $skip_reason = "$method died"; $exception = ''; } else { if ($self->fail_if_returned_early) { my $class = ref $self; $Builder->ok(0, "($class\::$method returned before plan complete)"); } else { $Builder->skip( $skip_reason ); } } } } return(_all_ok_from($self, $num_start)); } sub fail_if_returned_early { 0 } sub _show_header { my ($self, @tests) = @_; return if $Builder->has_plan; my $num_tests = Test::Class->expected_tests(@tests); if ($num_tests eq NO_PLAN) { $Builder->no_plan; } else { $Builder->expected_tests($num_tests); } } my %SKIP_THIS_CLASS = (); sub SKIP_CLASS { my $class = shift; $SKIP_THIS_CLASS{ $class } = shift if @_; return $SKIP_THIS_CLASS{ $class }; } sub _isa_class { my ( $class, $object_or_class ) = @_; return unless defined $object_or_class; return if $object_or_class eq 'Contextual::Return::Value'; return eval { $object_or_class->isa( $class ) and $object_or_class->can( 'runtests' ) }; } sub _test_classes { my $class = shift; return( @{mro::get_isarev($class)}, $class ); } sub runtests { die "Test::Class was loaded too late (after the CHECK block was run), or you may have redefined a test_ sub. See 'A NOTE ON LOADING TEST CLASSES' in perldoc Test::Class for more details\n" unless $Check_block_has_run; my @tests = @_; if (@tests == 1 && !ref($tests[0])) { my $base_class = shift @tests; @tests = _test_classes( $base_class ); } my $all_passed = 1; TEST_OBJECT: foreach my $t (@tests) { # SHOULD ALSO ALLOW NO_PLAN next if $t =~ m/^\d+$/; croak "$t is not Test::Class or integer" unless _isa_class( __PACKAGE__, $t ); if (my $reason = $t->SKIP_CLASS) { _show_header($t, @tests); $Builder->skip( $reason ) unless $reason eq "1"; } else { $t = $t->new unless ref($t); my @test_methods = _get_methods($t, TEST); if ( @test_methods ) { foreach my $method (_get_methods($t, STARTUP)) { _show_header($t, @tests) unless _has_no_tests($t, $method); my $method_passed = _run_method($t, $method, \@tests); $all_passed = 0 unless $method_passed; next TEST_OBJECT unless $method_passed; } my $class = ref($t); my @setup = _get_methods($t, SETUP); my @teardown = _get_methods($t, TEARDOWN); foreach my $test ( @test_methods ) { local $Current_method = $test; $Builder->diag("\n$class->$test") if $ENV{TEST_VERBOSE}; my @methods_to_run = (@setup, $test, @teardown); while ( my $method = shift @methods_to_run ) { _show_header($t, @tests) unless _has_no_tests($t, $method); $all_passed = 0 unless _run_method($t, $method, \@tests); if ( _threw_exception( $t, $method ) ) { next if ($method eq $test); my $num_to_skip = _total_num_tests($t, @methods_to_run); $Builder->skip( "$method died" ) for ( 1 .. $num_to_skip ); last; } } } foreach my $method (_get_methods($t, SHUTDOWN)) { _show_header($t, @tests) unless _has_no_tests($t, $method); $all_passed = 0 unless _run_method($t, $method, \@tests); } } } } return($all_passed); } sub _find_calling_test_class { my $level = 0; while (my $class = caller(++$level)) { next if $class eq __PACKAGE__; return $class if _isa_class( __PACKAGE__, $class ); } return(undef); } sub num_method_tests { my ($self, $method, $n) = @_; my $class = _find_calling_test_class( $self ) or croak "not called in a Test::Class"; my $info = _method_info($self, $class, $method) or croak "$method is not a test method of class $class"; $info->num_tests($n) if defined($n); return( $info->num_tests ); } sub num_tests { my $self = shift; croak "num_tests need to be called within a test method" unless defined $Current_method; return( $self->num_method_tests( $Current_method, @_ ) ); } sub BAILOUT { my ($self, $reason) = @_; $Builder->BAILOUT($reason); } sub _last_test_if_exiting_immediately { $Builder->expected_tests || $Builder->current_test+1 } sub FAIL_ALL { my ($self, $reason) = @_; my $last_test = _last_test_if_exiting_immediately(); $Builder->expected_tests( $last_test ) unless $Builder->has_plan; $Builder->ok(0, $reason) until $Builder->current_test >= $last_test; my $num_failed = $Builder->can("history") ? $Builder->history->fail_count : grep( !$_, $Builder->summary ); exit( $num_failed < 254 ? $num_failed : 254 ); } sub SKIP_ALL { my ($self, $reason) = @_; $Builder->skip_all( $reason ) unless $Builder->has_plan; my $last_test = _last_test_if_exiting_immediately(); $Builder->skip( $reason ) until $Builder->current_test >= $last_test; exit(0); } sub add_filter { my ( $class, $cb ) = @_; if ( not ref $cb eq 'CODE' ) { croak "Filter isn't a code-ref" } push @Filters, $cb; } 1; __END__ =head1 NAME Test::Class - Easily create test classes in an xUnit/JUnit style =head1 VERSION version 0.50 =head1 SYNOPSIS package Example::Test; use base qw(Test::Class); use Test::More; # setup methods are run before every test method. sub make_fixture : Test(setup) { my $array = [1, 2]; shift->{test_array} = $array; } # a test method that runs 1 test sub test_push : Test { my $array = shift->{test_array}; push @$array, 3; is_deeply($array, [1, 2, 3], 'push worked'); } # a test method that runs 4 tests sub test_pop : Test(4) { my $array = shift->{test_array}; is(pop @$array, 2, 'pop = 2'); is(pop @$array, 1, 'pop = 1'); is_deeply($array, [], 'array empty'); is(pop @$array, undef, 'pop = undef'); } # teardown methods are run after every test method. sub teardown : Test(teardown) { my $array = shift->{test_array}; diag("array = (@$array) after test(s)"); } later in a nearby .t file #! /usr/bin/perl use Example::Test; # run all the test methods in Example::Test Test::Class->runtests; Outputs: 1..5 ok 1 - pop = 2 ok 2 - pop = 1 ok 3 - array empty ok 4 - pop = undef # array = () after test(s) ok 5 - push worked # array = (1 2 3) after test(s) =head1 DESCRIPTION Test::Class provides a simple way of creating classes and objects to test your code in an xUnit style. Built using L, it was designed to work with other Test::Builder based modules (L, L, L, etc.). I This module will make more sense, if you are already familiar with the "standard" mechanisms for testing perl code. Those unfamiliar with L, L, L and friends should go take a look at them now. L is a good starting point. =head1 INTRODUCTION =head2 A brief history lesson In 1994 Kent Beck wrote a testing framework for Smalltalk called SUnit. It was popular. You can read a copy of his original paper at L. Later Kent Beck and Erich Gamma created JUnit for testing Java L. It was popular too. Now there are xUnit frameworks for every language from Ada to XSLT. You can find a list at L. While xUnit frameworks are traditionally associated with unit testing they are also useful in the creation of functional/acceptance tests. Test::Class is (yet another) implementation of xUnit style testing in Perl. =head2 Why you should use Test::Class Test::Class attempts to provide simple xUnit testing that integrates simply with the standard perl *.t style of testing. In particular: =over 4 =item * All the advantages of xUnit testing. You can easily create test fixtures and isolate tests. It provides a framework that should be familiar to people who have used other xUnit style test systems. =item * It is built with L and should co-exist happily with all other Test::Builder based modules. This makes using test classes in *.t scripts, and refactoring normal tests into test classes, much simpler because: =over 4 =item * You do not have to learn a new set of new test APIs and can continue using ok(), like(), etc. from L and friends. =item * Skipping tests and todo tests are supported. =item * You can have normal tests and Test::Class classes co-existing in the same *.t script. You don't have to re-write an entire script, but can use test classes as and when it proves useful. =back =item * You can easily package your tests as classes/modules, rather than *.t scripts. This simplifies reuse, documentation and distribution, encourages refactoring, and allows tests to be extended by inheritance. =item * You can have multiple setup/teardown methods. For example have one teardown method to clean up resources and another to check that class invariants still hold. =item * It can make running tests faster. Once you have refactored your *.t scripts into classes they can be easily run from a single script. This gains you the (often considerable) start up time that each separate *.t script takes. =back =head2 Why you should I use Test::Class =over 4 =item * If your *.t scripts are working fine then don't bother with Test::Class. For simple test suites it is almost certainly overkill. Don't start thinking about using Test::Class until issues like duplicate code in your test scripts start to annoy. =item * If you are distributing your code it is yet another module that the user has to have to run your tests (unless you distribute it with your test suite of course). =item * If you are used to the TestCase/Suite/Runner class structure used by JUnit and similar testing frameworks you may find Test::Unit more familiar (but try reading L before you give up). =back =head1 TEST CLASSES A test class is just a class that inherits from Test::Class. Defining a test class is as simple as doing: package Example::Test; use base qw(Test::Class); Since Test::Class does not provide its own test functions, but uses those provided by L and friends, you will nearly always also want to have: use Test::More; to import the test functions into your test class. =head1 METHOD TYPES There are three different types of method you can define using Test::Class. =head2 1) Test methods You define test methods using the L attribute. For example: package Example::Test; use base qw(Test::Class); use Test::More; sub subtraction : Test { is( 2-1, 1, 'subtraction works' ); } This declares the C method as a test method that runs one test. If your test method runs more than one test, you should put the number of tests in brackets like this: sub addition : Test(2) { is(10 + 20, 30, 'addition works'); is(20 + 10, 30, ' both ways'); } If you don't know the number of tests at compile time you can use C like this. sub check_class : Test(no_plan) { my $objects = shift->{objects}; isa_ok($_, "Object") foreach @$objects; } or use the :Tests attribute, which acts just like C<:Test> but defaults to C if no number is given: sub check_class : Tests { my $objects = shift->{objects}; isa_ok($_, "Object") foreach @$objects; } =head2 2) Setup and teardown methods Setup and teardown methods are run before and after every test. For example: sub before : Test(setup) { diag("running before test") } sub after : Test(teardown) { diag("running after test") } You can use setup and teardown methods to create common objects used by all of your test methods (a test I) and store them in your Test::Class object, treating it as a hash. For example: sub pig : Test(setup) { my $self = shift; $self->{test_pig} = Pig->new; } sub born_hungry : Test { my $pig = shift->{test_pig}; is($pig->hungry, 'pigs are born hungry'); } sub eats : Test(3) { my $pig = shift->{test_pig}; ok( $pig->feed, 'pig fed okay'); ok(! $pig->hungry, 'fed pig not hungry'); ok(! $pig->feed, 'cannot feed full pig'); } You can also declare setup and teardown methods as running tests. For example you could check that the test pig survives each test method by doing: sub pig_alive : Test(teardown => 1) { my $pig = shift->{test_pig}; ok($pig->alive, 'pig survived tests' ); } =head2 3) Startup and shutdown methods Startup and shutdown methods are like setup and teardown methods for the whole test class. All the startup methods are run once when you start running a test class. All the shutdown methods are run once just before a test class stops running. You can use these to create and destroy expensive objects that you don't want to have to create and destroy for every test - a database connection for example: sub db_connect : Test(startup) { shift->{dbi} = DBI->connect; } sub db_disconnect : Test(shutdown) { shift->{dbi}->disconnect; } Just like setup and teardown methods you can pass an optional number of tests to startup and shutdown methods. For example: sub example : Test(startup => 1) { ok(1, 'a startup method with one test'); } If you want to run an unknown number of tests within your startup method, you need to say e.g. sub example : Test(startup => no_plan) { ok(1, q{The first of many tests that don't want to have to count}); ... } as the : Tests attribute behaves exactly like : Test in this context. If a startup method has a failing test or throws an exception then all other tests for the current test object are ignored. =head1 RUNNING TESTS You run test methods with L. Doing: Test::Class->runtests runs all of the test methods in every loaded test class. This allows you to easily load multiple test classes in a *.t file and run them all. #! /usr/bin/perl # load all the test classes I want to run use Foo::Test; use Foo::Bar::Test; use Foo::Fribble::Test; use Foo::Ni::Test; # and run them all Test::Class->runtests; You can use L to automatically load all the test classes in a given set of directories. If you need finer control you can create individual test objects with L. For example to just run the tests in the test class C you can do: Example::Test->new->runtests You can also pass L a list of test objects to run. For example: my $o1 = Example::Test->new; my $o2 = Another::Test->new; # runs all the tests in $o1 and $o2 $o1->runtests($o2); Since, by definition, the base Test::Class has no tests, you could also have written: my $o1 = Example::Test->new; my $o2 = Another::Test->new; Test::Class->runtests($o1, $o2); If you pass L class names it will automatically create test objects for you, so the above can be written more compactly as: Test::Class->runtests(qw( Example::Test Another::Test )) In all of the above examples L will look at the number of tests both test classes run and output an appropriate test header for L automatically. What happens if you run test classes and normal tests in the same script? For example: Test::Class->runtests; ok(Example->new->foo, 'a test not in the test class'); ok(Example->new->bar, 'ditto'); L will complain that it saw more tests than it expected since the test header output by L will not include the two normal tests. To overcome this problem you can pass an integer value to L. This is added to the total number of tests in the test header. So the problematic example can be rewritten as follows: Test::Class->runtests(+2); ok(Example->new->foo, 'a test not in the test class'); ok(Example->new->bar, 'ditto'); If you prefer to write your test plan explicitly you can use L to find out the number of tests a class/object is expected to run. Since L will not output a test plan if one has already been set, the previous example can be written as: plan tests => Test::Class->expected_tests(+2); Test::Class->runtests; ok(Example->new->foo, 'a test not in the test class'); ok(Example->new->bar, 'ditto'); I Test objects are just normal perl objects. Test classes are just normal perl classes. Setup, test and teardown methods are just normal methods. You are completely free to have other methods in your class that are called from your test methods, or have object specific C and C methods. In particular you can override the new() method to pass parameters to your test object, or re-define the number of tests a method will run. See L for an example. =head1 TEST DESCRIPTIONS The test functions you import from L and other L based modules usually take an optional third argument that specifies the test description, for example: is $something, $something_else, 'a description of my test'; If you do not supply a test description, and the test function does not supply its own default, then Test::Class will use the name of the currently running test method, replacing all "_" characters with spaces so: sub one_plus_one_is_two : Test { is 1+1, 2; } will result in: ok 1 - one plus one is two =head1 RUNNING ORDER OF METHODS Methods of each type are run in the following order: =over 4 =item 1. All of the startup methods in alphabetical order =item 2. For each test method, in alphabetical order: =over 2 =item * All of the setup methods in alphabetical order =item * The test method. =item * All of the teardown methods in alphabetical order =back =item 3. All of the shutdown methods in alphabetical order. =back Most of the time you should not care what order tests are run in, but it can occasionally be useful to force some test methods to be run early. For example: sub _check_new { my $self = shift; isa_ok(Object->new, "Object") or $self->BAILOUT('new fails!'); } The leading C<_> will force the above method to run first - allowing the entire suite to be aborted before any other test methods run. =head1 HANDLING EXCEPTIONS If a startup, setup, test, teardown or shutdown method dies then L will catch the exception and fail any remaining test. For example: sub test_object : Test(2) { my $object = Object->new; isa_ok( $object, "Object" ) or die "could not create object\n"; ok( $object->open, "open worked" ); } will produce the following if the first test failed: not ok 1 - The object isa Object # Failed test 'The object isa Object' # at /Users/adrianh/Desktop/foo.pl line 14. # (in MyTest->test_object) # The object isn't defined not ok 2 - test_object died (could not create object) # Failed test 'test_object died (could not create object)' # at /Users/adrianh/Desktop/foo.pl line 19. # (in MyTest->test_object) This can considerably simplify testing code that throws exceptions. Rather than having to explicitly check that the code exited normally (e.g. with L) the test will fail automatically - without aborting the other test methods. For example contrast: use Test::Exception; my $file; lives_ok { $file = read_file('test.txt') } 'file read'; is($file, "content", 'test file read'); with: sub read_file : Test { is(read_file('test.txt'), "content", 'test file read'); } If more than one test remains after an exception then the first one is failed, and the remaining ones are skipped. If the setup method of a test method dies, then all of the remaining setup and shutdown methods are also skipped. Since startup methods will usually be creating state needed by all the other test methods, an exception within a startup method will prevent all other test methods of that class running. =head1 RETURNING EARLY If a test method returns before it has run all of its tests, by default the missing tests are deemed to have been skipped; see L<"Skipped Tests"> for more information. However, if the class's C method returns true, then the missing tests will be deemed to have failed. For example, package MyClass; use base 'Test::Class'; sub fail_if_returned_early { 1 } sub oops : Tests(8) { for (my $n=1; $n*$n<50; ++$n) { ok 1, "$n squared is less than fifty"; } } =head1 SKIPPED TESTS You can skip the rest of the tests in a method by returning from the method before all the test have finished running (but see L<"Returning Early"> for how to change this). The value returned is used as the reason for the tests being skipped. This makes managing tests that can be skipped for multiple reasons very simple. For example: sub flying_pigs : Test(5) { my $pig = Pig->new; isa_ok($pig, 'Pig') or return("cannot breed pigs") can_ok($pig, 'takeoff') or return("pigs don't fly here"); ok($pig->takeoff, 'takeoff') or return("takeoff failed"); ok( $pig->altitude > 0, 'Pig is airborne' ); ok( $pig->airspeed > 0, ' and moving' ); } If you run this test in an environment where Cnew> worked and the takeoff method existed, but failed when ran, you would get: ok 1 - The object isa Pig ok 2 - can takeoff not ok 3 - takeoff ok 4 # skip takeoff failed ok 5 # skip takeoff failed You can also skip tests just as you do in Test::More or Test::Builder - see L for more information. I if you want to skip tests in a method with C tests then you have to explicitly skip the tests in the method - since Test::Class cannot determine how many tests (if any) should be skipped: sub test_objects : Tests { my $self = shift; my $objects = $self->{objects}; if (@$objects) { isa_ok($_, "Object") foreach (@$objects); } else { $self->builder->skip("no objects to test"); } } Another way of overcoming this problem is to explicitly set the number of tests for the method at run time using L or L<"num_tests">. You can make a test class skip all of its tests by setting L before L is called. =head1 TO DO TESTS You can create todo tests just as you do in L and L using the C<$TODO> variable. For example: sub live_test : Test { local $TODO = "live currently unimplemented"; ok(Object->live, "object live"); } See L for more information. =head1 EXTENDING TEST CLASSES BY INHERITANCE You can extend test methods by inheritance in the usual way. For example consider the following test class for a C object. package Pig::Test; use base qw(Test::Class); use Test::More; sub testing_class { "Pig" } sub new_args { (-age => 3) } sub setup : Test(setup) { my $self = shift; my $class = $self->testing_class; my @args = $self->new_args; $self->{pig} = $class->new( @args ); } sub _creation : Test { my $self = shift; isa_ok($self->{pig}, $self->testing_class) or $self->FAIL_ALL('Pig->new failed'); } sub check_fields : Test { my $pig = shift->{pig} is($pig->age, 3, "age accessed"); } Next consider C a subclass of C where you can give your pig a name. We want to make sure that all the tests for the C object still work for C. We can do this by subclassing C and overriding the C and C methods. package NamedPig::Test; use base qw(Pig::Test); use Test::More; sub testing_class { "NamedPig" } sub new_args { (shift->SUPER::new_args, -name => 'Porky') } Now we need to test the name method. We could write another test method, but we also have the option of extending the existing C method. sub check_fields : Test(2) { my $self = shift; $self->SUPER::check_fields; is($self->{pig}->name, 'Porky', 'name accessed'); } While the above works, the total number of tests for the method is dependent on the number of tests in its C. If we add a test to Ccheck_fields> we will also have to update the number of tests of Ccheck_fields>. Test::Class allows us to state explicitly that we are adding tests to an existing method by using the C<+> prefix. Since we are adding a single test to C, it can be rewritten as: sub check_fields : Test(+1) { my $self = shift; $self->SUPER::check_fields; is($self->{pig}->name, 'Porky', 'name accessed'); } With the above definition you can add tests to C in C without affecting C. =head1 RUNNING INDIVIDUAL TESTS B The exact mechanism for running individual tests is likely to change in the future. Sometimes you just want to run a single test. Commenting out other tests or writing code to skip them can be a hassle, so you can specify the C environment variable. The value is expected to be a valid regular expression and, if present, only runs test methods whose names match the regular expression. Startup, setup, teardown and shutdown tests will still be run. One easy way of doing this is by specifying the environment variable I the C method is called. Running a test named C: #! /usr/bin/perl use Example::Test; $ENV{TEST_METHOD} = 'customer_profile'; Test::Class->runtests; Running all tests with C in their name: #! /usr/bin/perl use Example::Test; $ENV{TEST_METHOD} = '.*customer.*'; Test::Class->runtests; If you specify an invalid regular expression, your tests will not be run: #! /usr/bin/perl use Example::Test; $ENV{TEST_METHOD} = 'C++'; Test::Class->runtests; And when you run it: TEST_METHOD (C++) is not a valid regular expression: Search pattern \ not terminated at (eval 17) line 1. =head1 ORGANISING YOUR TEST CLASSES You can, of course, organise your test modules as you wish. My personal preferences is: =over 4 =item * Name test classes with a suffix of C<::Test> so the test class for the C module would be C. =item * Place all test classes in F. =back The L provides a simple mechanism for easily loading all of the test classes in a given set of directories. =head1 A NOTE ON LOADING TEST CLASSES Due to its use of subroutine attributes Test::Class based modules must be loaded at compile rather than run time. This is because the :Test attribute is applied by a CHECK block. This can be problematic if you want to dynamically load Test::Class modules. Basically while: require $some_test_class; will break, doing: BEGIN { require $some_test_class } will work just fine. For more information on CHECK blocks see L. If you still can't arrange for your classes to be loaded at runtime, you could use an alternative mechanism for adding your tests: # sub test_something : Test(3) {...} # becomes sub test_something {...} __PACKAGE__->add_testinfo('test_something', test => 3); See the L method for more details. Additionally, if you've forgotten to enable warnings and have two test subs called the same thing, you will get the same error. =head1 GENERAL FILTERING OF TESTS The use of $ENV{TEST_METHOD} to run just a subset of tests is useful, but sometimes it doesn't give the level of granularity that you desire. Another feature of this class is the ability to do filtering on other static criteria. In order to permit this, a generic filtering method is supported. This can be used by specifying coderefs to the 'add_filter' method of this class. In determining which tests should be run, all filters that have previously been specified via the add_filter method will be run in-turn for each normal test method. If B of these filters return a false value, the method will not be executed, or included in the number of tests. Note that filters will only be run for normal test methods, they are ignored for startup, shutdown, setup, and teardown test methods. Note that test filters are global, and will affect all tests in all classes, not just the one that they were defined in. An example of this mechanism that mostly simulates the use of TEST_METHOD above is: package MyTests; use Test::More; use base qw( Test::Class ); my $MYTEST_METHOD = qr/^t_not_filtered$/; my $filter = sub { my ( $test_class, $test_method ) = @_; return $test_method =~ $MYTEST_METHOD; } Test::Class->add_filter( $filter ); sub t_filtered : Test( 1 ) { fail( "filtered test run" ); } sub t_not_filtered : Test( 1 ) { pass( "unfiltered test run" ); } =head1 METHODS =head2 Creating and running tests =over 4 =item B # test methods sub method_name : Test { ... } sub method_name : Test(N) { ... } # setup methods sub method_name : Test(setup) { ... } sub method_name : Test(setup => N) { ... } # teardown methods sub method_name : Test(teardown) { ... } sub method_name : Test(teardown => N) { ... } # startup methods sub method_name : Test(startup) { ... } sub method_name : Test(startup => N) { ... } # shutdown methods sub method_name : Test(shutdown) { ... } sub method_name : Test(shutdown => N) { ... } Marks a startup, setup, test, teardown or shutdown method. See L for information on how to run methods declared with the C attribute. N specifies the number of tests the method runs. =over 4 =item * If N is an integer then the method should run exactly N tests. =item * If N is an integer with a C<+> prefix then the method is expected to call its C method and extend it by running N additional tests. =item * If N is the string C then the method can run an arbitrary number of tests. =back If N is not specified it defaults to C<1> for test methods, and C<0> for startup, setup, teardown and shutdown methods. You can change the number of tests that a method runs using L or L. =item B sub method_name : Tests { ... } sub method_name : Tests(N) { ... } Acts just like the C<:Test> attribute, except that if the number of tests is not specified it defaults to C. So the following are equivalent: sub silly1 :Test( no_plan ) { ok(1) foreach (1 .. rand 5) } sub silly2 :Tests { ok(1) foreach (1 .. rand 5) } =item B $Tests = CLASS->new(KEY => VAL ...) $Tests2 = $Tests->new(KEY => VAL ...) Creates a new test object (blessed hashref) containing the specified key/value pairs. If called as an object method the existing object's key/value pairs are copied into the new object. Any key/value pairs passed to C override those in the original object if duplicates occur. Since the test object is passed to every test method as it runs, it is a convenient place to store test fixtures. For example: sub make_fixture : Test(setup) { my $self = shift; $self->{object} = Object->new(); $self->{dbh} = Mock::DBI->new(-type => normal); } sub test_open : Test { my $self = shift; my ($o, $dbh) = ($self->{object}, $self->{dbh}); ok($o->open($dbh), "opened ok"); } See L for an example of overriding C. =item B $n = $Tests->expected_tests $n = CLASS->expected_tests $n = $Tests->expected_tests(TEST, ...) $n = CLASS->expected_tests(TEST, ...) Returns the total number of tests that L will run on the specified class/object. This includes tests run by any setup and teardown methods. Will return C if the exact number of tests is undetermined (i.e. if any setup, test or teardown method has an undetermined number of tests). The C of an object after L has been executed will include any run time changes to the expected number of tests made by L or L. C can also take an optional list of test objects, test classes and integers. In this case the result is the total number of expected tests for all the test/object classes (including the one the method was applied to) plus any integer values. C is useful when you're integrating one or more test classes into a more traditional test script, for example: use Test::More; use My::Test::Class; plan tests => My::Test::Class->expected_tests(+2); ok(whatever, 'a test'); ok(whatever, 'another test'); My::Test::Class->runtests; =item B $allok = $Tests->runtests $allok = CLASS->runtests $allok = $Tests->runtests(TEST, ...) $allok = CLASS->runtests(TEST, ...) C is used to run test classes. At its most basic doing: $test->runtests will run the test methods of the test object $test, unless C<< $test->SKIP_CLASS >> returns a true value. Unless you have already specified a test plan using Test::Builder (or Test::More, et al) C will set the test plan just before the first method that runs a test is executed. If the environment variable C is set C will display the name of each test method before it runs like this: # My::Test::Class->my_test ok 1 - fribble # My::Test::Class->another_test ok 2 - bar Just like L, C can take an optional list of test object/classes and integers. All of the test object/classes are run. Any integers are added to the total number of tests shown in the test header output by C. For example, you can run all the tests in test classes A, B and C, plus one additional normal test by doing: Test::Class->runtests(qw(A B C), +1); ok(1==1, 'non class test'); Finally, if you call C on a test class without any arguments it will run all of the test methods of that class, and all subclasses of that class. For example: #! /usr/bin/perl # Test all the Foo stuff use Foo::Test; use Foo::Bar::Test; use Foo::Ni::Test; # run all the Foo*Test modules we just loaded Test::Class->runtests; =item B $reason = CLASS->SKIP_CLASS; CLASS->SKIP_CLASS( $reason ); Determines whether the test class CLASS should run it's tests. If SKIP_CLASS returns a true value then L will not run any of the test methods in CLASS. You can override the default on a class-by-class basis by supplying a new value to SKIP_CLASS. For example if you have an abstract base class that should not run just add the following to your module: My::Abstract::Test->SKIP_CLASS( 1 ); This will not affect any sub-classes of C which will run as normal. If the true value returned by SKIP_CLASS is anything other than "1" then a skip test is output using this value as the skip message. For example: My::Postgres::Test->SKIP_CLASS( $ENV{POSTGRES_HOME} ? 0 : '$POSTGRES_HOME needs to be set' ); will output something like this if C is not set ... other tests ... ok 123 # skip My::Postgres::Test - $POSTGRES_HOME needs to be set ... more tests ... You can also override SKIP_CLASS for a class hierarchy. For example, to prevent any subclasses of My::Postgres::Test running we could override SKIP_CLASS like this: sub My::Postgres::Test::SKIP_CLASS { $ENV{POSTGRES_HOME} ? 0 : '$POSTGRES_HOME needs to be set' } =back =head2 Fetching and setting a method's test number =over 4 =item B $n = $Tests->num_method_tests($method_name) $Tests->num_method_tests($method_name, $n) $n = CLASS->num_method_tests($method_name) CLASS->num_method_tests($method_name, $n) Fetch or set the number of tests that the named method is expected to run. If the method has an undetermined number of tests then $n should be the string C. If the method is extending the number of tests run by the method in a superclass then $n should have a C<+> prefix. When called as a class method any change to the expected number of tests applies to all future test objects. Existing test objects are unaffected. When called as an object method any change to the expected number of tests applies to that object alone. C is useful when you need to set the expected number of tests at object creation time, rather than at compile time. For example, the following test class will run a different number of tests depending on the number of objects supplied. package Object::Test; use base qw(Test::Class); use Test::More; sub new { my $class = shift; my $self = $class->SUPER::new(@_); my $num_objects = @{$self->{objects}}; $self->num_method_tests('test_objects', $num_objects); return($self); } sub test_objects : Tests { my $self = shift; ok($_->open, "opened $_") foreach @{$self->{objects}}; } ... # This runs two tests Object::Test->new(objects => [$o1, $o2]); The advantage of setting the number of tests at object creation time, rather than using a test method without a plan, is that the number of expected tests can be determined before testing begins. This allows better diagnostics from L, L and L. C is a protected method and can only be called by subclasses of Test::Class. It fetches or sets the expected number of tests for the methods of the class it was I, not the methods of the object/class it was I. This allows test classes that use C to be subclassed easily. For example, consider the creation of a subclass of Object::Test that ensures that all the opened objects are read-only: package Special::Object::Test; use base qw(Object::Test); use Test::More; sub test_objects : Test(+1) { my $self = shift; $self->SUPER::test_objects; my @bad_objects = grep {! $_->read_only} (@{$self->{objects}}); ok(@bad_objects == 0, "all objects read only"); } ... # This runs three tests Special::Object::Test->new(objects => [$o1, $o2]); Since the call to C in Object::Test only affects the C of Object::Test, the above works as you would expect. =item B $n = $Tests->num_tests $Tests->num_tests($n) $n = CLASS->num_tests CLASS->num_tests($n) Set or return the number of expected tests associated with the currently running test method. This is the same as calling L with a method name of L. For example: sub txt_files_readable : Tests { my $self = shift; my @files = <*.txt>; $self->num_tests(scalar(@files)); ok(-r $_, "$_ readable") foreach (@files); } Setting the number of expected tests at run time, rather than just having a C test method, allows L to display appropriate diagnostic messages if the method runs a different number of tests. =back =head2 Support methods =over 4 =item B $Tests->builder Returns the underlying L object that Test::Class uses. For example: sub test_close : Test { my $self = shift; my ($o, $dbh) = ($self->{object}, $self->{dbh}); $self->builder->ok($o->close($dbh), "closed ok"); } =item B $method_name = $Tests->current_method $method_name = CLASS->current_method Returns the name of the test method currently being executed by L, or C if L has not been called. The method name is also available in the setup and teardown methods that run before and after the test method. This can be useful in producing diagnostic messages, for example: sub test_invarient : Test(teardown => 1) { my $self = shift; my $m = $self->current_method; ok($self->invarient_ok, "class okay after $m"); } =item B $Tests->BAILOUT($reason) CLASS->BAILOUT($reason) Things are going so badly all testing should terminate, including running any additional test scripts invoked by L. This is exactly the same as doing: $self->builder->BAILOUT See L for details. Any teardown and shutdown methods are I run. =item B $Tests->FAIL_ALL($reason) CLASS->FAIL_ALL($reason) Things are going so badly all the remaining tests in the current script should fail. Exits immediately with the number of tests failed, or C<254> if more than 254 tests were run. Any teardown methods are I run. This does not affect the running of any other test scripts invoked by L. For example, if all your tests rely on the ability to create objects then you might want something like this as an early test: sub _test_new : Test(3) { my $self = shift; isa_ok(Object->new, "Object") || $self->FAIL_ALL('cannot create Objects'); ... } =item B $Tests->SKIP_ALL($reason) CLASS->SKIP_ALL($reason) Things are going so badly all the remaining tests in the current script should be skipped. Exits immediately with C<0> - teardown methods are I run. This does not affect the running of any other test scripts invoked by L. For example, if you had a test script that only applied to the darwin OS you could write: sub _darwin_only : Test(setup) { my $self = shift; $self->SKIP_ALL("darwin only") unless $^O eq "darwin"; } =item B CLASS->add_testinfo($name, $type, $num_tests) Chiefly for use by libraries like L, which can't use the C<:Test(...)> interfaces make test methods. C informs the class about a test method that has been defined without a C, C or other attribute. C<$name> is the name of the method, C<$type> must be one of C, C, C, C or C, and C<$num_tests> has the same meaning as C in the description of the L attribute. =item B CLASS->add_filter($filter_coderef); Adds a filtering coderef. Each filter is passed a test class and method name and returns a boolean. All filters are applied globally in the order they were added. If any filter returns false the test method is not run or included in the number of tests. Note that filters will only be run for normal test methods, they are ignored for startup, shutdown, setup, and teardown test methods. See the section on the L for more information. =item B Controls what happens if a method returns before it has run all of its tests. It is called with no arguments in boolean context; if it returns true, then the missing tests fail, otherwise, they skip. See L<"Returning Early"> and L<"Skipped Tests">. =back =head1 HELP FOR CONFUSED JUNIT USERS This section is for people who have used JUnit (or similar) and are confused because they don't see the TestCase/Suite/Runner class framework they were expecting. Here we take each of the major classes in JUnit and compare them with their equivalent Perl testing modules. =over 4 =item B The test assertions provided by Assert correspond to the test functions provided by the L based modules (L, L, L, etc.) Unlike JUnit the test functions supplied by Test::More et al do I throw exceptions on failure. They just report the failure to STDOUT where it is collected by L. This means that where you have sub foo : Test(2) { ok($foo->method1); ok($foo->method2); } The second test I run if the first one fails. You can emulate the JUnit way of doing it by throwing an explicit exception on test failure: sub foo : Test(2) { ok($foo->method1) or die "method1 failed"; ok($foo->method2); } The exception will be caught by Test::Class and the other test automatically failed. =item B Test::Class corresponds to TestCase in JUnit. In Test::Class setup, test and teardown methods are marked explicitly using the L attribute. Since we need to know the total number of tests to provide a test plan for L, we also state how many tests each method runs. Unlike JUnit you can have multiple setup/teardown methods in a class. =item B Test::Class also does the work that would be done by TestSuite in JUnit. Since the methods are marked with attributes, Test::Class knows what is and isn't a test method. This allows it to run all the test methods without having the developer create a suite manually, or use reflection to dynamically determine the test methods by name. See the L method for more details. The running order of the test methods is fixed in Test::Class. Methods are executed in alphabetical order. To run individual test methods, see L. =item B L does the work of the TestRunner in JUnit. It collects the test results (sent to STDOUT) and collates the results. Unlike JUnit there is no distinction made by Test::Harness between errors and failures. However, it does support skipped and todo test - which JUnit does not. If you want to write your own test runners you should look at L. =back =head1 OTHER MODULES FOR XUNIT TESTING IN PERL In addition to Test::Class there are two other distributions for xUnit testing in perl. Both have a longer history than Test::Class and might be more suitable for your needs. I am biased since I wrote Test::Class - so please read the following with appropriate levels of scepticism. If you think I have misrepresented the modules please let me know. =over 4 =item B A very simple unit testing framework. If you are looking for a lightweight single module solution this might be for you. The advantage of L is that it is simple! Just one module with a smallish API to learn. Of course this is also the disadvantage. It's not class based so you cannot create testing classes to reuse and extend. It doesn't use L so it's difficult to extend or integrate with other testing modules. If you are already familiar with L, L and friends you will have to learn a new test assertion API. It does not support L. =item B L is a port of JUnit L into perl. If you have used JUnit then the Test::Unit framework should be very familiar. It is class based so you can easily reuse your test classes and extend by subclassing. You get a nice flexible framework you can tweak to your heart's content. If you can run Tk you also get a graphical test runner. However, Test::Unit is not based on L. You cannot easily move Test::Builder based test functions into Test::Unit based classes. You have to learn another test assertion API. Test::Unit implements it's own testing framework separate from L. You can retrofit *.t scripts as unit tests, and output test results in the format that L expects, but things like L and L are not supported. =back =head1 BUGS None known at the time of writing. If you find any bugs please let me know by e-mail at , or report the problem with L. =head1 COMMUNITY =head2 perl-qa If you are interested in testing using Perl I recommend you visit L and join the excellent perl-qa mailing list. See L for details on how to subscribe. =head2 perlmonks You can find users of Test::Class, including the module author, on L. Feel free to ask questions on Test::Class there. =head2 CPAN::Forum The CPAN Forum is a web forum for discussing Perl's CPAN modules. The Test::Class forum can be found at L. =head1 TO DO If you think this module should do something that it doesn't (or does something that it shouldn't) please let me know. You can see my current to do list at L, with an RSS feed of changes at L. =head1 ACKNOWLEDGMENTS This is yet another implementation of the ideas from Kent Beck's Testing Framework paper L. Thanks to Adam Kennedy, agianni, Alexander D'Archangel, Andrew Grangaard, Apocalypse, Ask Bjorn Hansen, Chris Dolan, Chris Williams, Corion, Cosimo Streppone, Daniel Berger, Dave Evans, Dave O'Neill, David Cantrell, David Wheeler, Diab Jerius, Emil Jansson, Gunnar Wolf, Hai Pham, Hynek, imacat, Jeff Deifik, Jim Brandt, Jochen Stenzel, Johan Lindstrom, John West, Jonathan R. Warden, Joshua ben Jore, Jost Krieger, Ken Fox, Kenichi Ishigaki Lee Goddard, Mark Morgan, Mark Reynolds, Mark Stosberg, Martin Ferrari, Mathieu Sauve-Frankel, Matt Trout, Matt Williamson, Michael G Schwern, Murat Uenalan, Naveed Massjouni, Nicholas Clark, Ovid, Piers Cawley, Rob Kinyon, Sam Raymer, Scott Lanning, Sebastien Aperghis-Tramoni, Steve Kirkup, Stray Toaster, Ted Carnahan, Terrence Brannon, Todd W, Tom Metro, Tony Bowden, Tony Edwardson, William McKee, various anonymous folk and all the fine people on perl-qa for their feedback, patches, suggestions and nagging. This module wouldn't be possible without the excellent L. Thanks to chromatic and Michael G Schwern for creating such a useful module. =head1 AUTHORS Adrian Howard , Curtis "Ovid" Poe, , Mark Morgan . If you use this module, and can spare the time please let us know or rate it at L. =head1 SEE ALSO =over 4 =item L Simple way to load "Test::Class" classes automatically. =item L Test::Class with additional conveniences to reduce need for some boilerplate code. Also makes L testing functions available. =item L Testing framework allows you to write your tests in Moose and test Moose and non-Moose code. It offers reporting, extensibility, test inheritance, parallel testing and more. =item L Delicious links on Test::Class. =item Perl Testing: A Developer's Notebook by Ian Langworth and chromatic Chapter 8 covers using Test::Class. =item Advanced Perl Programming, second edition by Simon Cozens Chapter 8 has a few pages on using Test::Class. =item The Perl Journal, April 2003 Includes the article "Test-Driven Development in Perl" by Piers Cawley that uses Test::Class. =item Test::Class Tutorial series written by Curtis "Ovid" Poe =over 4 =item * L =item * L =item * L =item * L =item * L =back =item L Support module for building test libraries. =item L & L Basic utilities for writing tests. =item L Overview of some of the many testing modules available on CPAN. =item L Delicious links on perl testing. =item L Another approach to object oriented testing. =item L and L Alternatives to grouping sets of tests together. =back The following modules use Test::Class as part of their test suite. You might want to look at them for usage examples: =over 4 L, L, Bricolage (L), L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, and L =back The following modules are not based on L, but may be of interest as alternatives to Test::Class. =over 4 =item L Perl unit testing framework closely modeled on JUnit. =item L A very simple unit testing framework. =back =head1 LICENCE Copyright 2002-2010 Adrian Howard, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Test-Class-0.50/lib/Test/Class/Load.pm000644 000766 000024 00000015011 12534676162 017654 0ustar00etherstaff000000 000000 use strict; use warnings; package Test::Class::Load; use Test::Class; use File::Find; use File::Spec; use Module::Runtime 'require_module'; our $VERSION = '0.50'; # Override to get your own filter sub is_test_class { my ( $class, $file, $dir ) = @_; # By default, we only care about .pm files if ($file =~ /\.pm$/) { return 1; } return; } my %Added_to_INC; sub _load { my ( $class, $file, $dir ) = @_; $file =~ s{\.pm$}{}; # remove .pm extension $file =~ s{\\}{/}g; # to make win32 happy $dir =~ s{\\}{/}g; # to make win32 happy $file =~ s/^$dir//; my $_package = join '::' => grep $_ => File::Spec->splitdir( $file ); # untaint that puppy! my ( $package ) = $_package =~ /^([[:word:]]+(?:::[[:word:]]+)*)$/; # Filter out bad classes (mainly this means things in .svn and similar) return unless defined $package; unshift @INC => $dir unless $Added_to_INC{ $dir }++; require_module($package); } sub import { my ( $class, @directories ) = @_; my @test_classes; foreach my $dir ( @directories ) { $dir = File::Spec->catdir( split '/', $dir ); find( { no_chdir => 1, wanted => sub { my @args = ($File::Find::name, $dir); if ($class->is_test_class(@args)) { $class->_load(@args); } }, }, $dir ); } } 1; __END__ =head1 NAME Test::Class::Load - Load C classes automatically. =head1 VERSION version 0.50 =head1 SYNOPSIS use Test::Class::Load qw(t/tests t/lib); Test::Class->runtests; =head1 EXPORT None. =head1 DESCRIPTION C typically uses a helper script to load the test classes. It often looks something like this: #!/usr/bin/perl -T use strict; use warnings; use lib 't/tests'; use MyTest::Foo; use MyTest::Foo::Bar; use MyTest::Foo::Baz; Test::Class->runtests; This 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. C automatically finds and loads your test classes for you. There is no longer a need to list them individually. =head1 BASIC USAGE Using C is as simple as this: #!/usr/bin/perl -T use strict; use warnings; use Test::Class::Load 't/tests'; Test::Class->runtests; That will search through all files in the C directory and automatically load anything which ends in C<.pm>. You should only put test classes in those directories. If you have test classes in more than one directory, that's OK. Just list all of them in the import list. use Test::Class::Load qw< t/customer t/order t/inventory >; Test::Class->runtests; =head1 ADVANCED USAGE Here's some examples of advanced usage of C. =head2 FILTER LOADED CLASSES You can redefine the filtering criteria, that is, decide what classes are picked up and what others are not. You do this simply by subclassing C overriding the C method. You might want to do this to only load modules which inherit from C, or anything else for that matter. =over 4 =item B $is_test_class = $class->is_test_class( $file, $directory ) Returns true if C<$file> in C<$directory> should be considered a test class and be loaded by L. The default filter simply returns true if C<$file> ends with C<.pm> =back For example: use strict; use warnings; package My::Loader; use base qw( Test::Class::Load ); # Overriding this selects what test classes # are considered by T::C::Load sub is_test_class { my ( $class, $file, $dir ) = @_; # return unless it's a .pm (the default) return unless $class->SUPER::is_test_class( $file, $dir ); # and only allow .pm files with "Good" in their filename return $file =~ m{Good}; } 1; =head2 CUSTOMIZING TEST RUNS One problem with this style of testing is that you run I 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 call: #!/usr/bin/perl -T use strict; use warnings; use Test::Class::Load 't/tests'; Then, 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: package My::Test::Class; use strict; use warnings; use base 'Test::Class'; INIT { Test::Class->runtests } # here's the magic! 1; Then you can run an individual test class by using the C utility, tell it the directory of the test classes and the name of the test package you wish to run: prove -lv -It/tests Some::Test::Class You can even automate this by binding it to a key in C: noremap ,t :!prove -lv -It/tests % Then 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 style script). Of course, you can still run your helper script with C, C or C<./Build test> to run all of your test classes. If you do that, you'll have to make sure that the C<-I> switches point to your test class directories. =head1 SECURITY C 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. my ($package) = $_package =~ /^([[:word:]]+(?:::[[:word:]]+)*)$/; =head1 AUTHOR Curtis "Ovid" Poe, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 ACKNOWLEDGMENTS Thanks to David Wheeler for the idea and Adrian Howard for C. =head1 COPYRIGHT & LICENSE Copyright 2006 Curtis "Ovid" Poe, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Test-Class-0.50/lib/Test/Class/MethodInfo.pm000644 000766 000024 00000004746 12534676162 021046 0ustar00etherstaff000000 000000 use strict; use warnings; package Test::Class::MethodInfo; use Carp; our $VERSION = '0.50'; sub new { my ( $class, %param ) = @_; my $self = bless { name => $param{ name }, type => $param{ type } || 'test', }, $class; unless ( defined $param{num_tests} ) { $param{ num_tests } = $self->is_type('test') ? 1 : 0; }; $self->num_tests( $param{num_tests} ); return $self; }; sub name { shift->{name} }; sub type { shift->{type} }; sub num_tests { my ( $self, $n ) = @_; if ( defined $n ) { croak "$n not valid number of tests" unless $self->is_num_tests($n); $self->{ num_tests } = $n; }; return $self->{ num_tests }; }; sub is_type { my ( $self, $type ) = @_; return $self->{ type } eq $type; }; sub is_method_type { my ( $self, $type ) = @_; return $type =~ m/^(startup|setup|test|teardown|shutdown)$/s; }; sub is_num_tests { my ( $self, $num_tests ) = @_; return $num_tests =~ m/^(no_plan)|(\+?\d+)$/s; }; 1; __END__ =head1 NAME Test::Class::MethodInfo - the info associated with a test method =head1 VERSION version 0.50 =head1 SYNOPSIS # Secret internal class # not for public use =head1 DESCRIPTION Holds info related to particular test methods. Not part of the public API and likely to change or completely disappear. If you need to rely on any of this code let me know and we'll see if we can work something out. =head1 METHODS =over 4 =item B =item B =item B =item B =item B =item B =item B =back =head1 BUGS None known at the time of writing. Apart from the fact this seems a bit gnarly so I'm likely to tidy it up at some point. If you find any please let me know by e-mail, or report the problem with L. =head1 TO DO If you think this module should do something that it doesn't (or does something that it shouldn't) please let me know. You can see my current to do list at L, with an RSS feed of changes at L. =head1 AUTHOR Adrian Howard If you can spare the time, please drop me a line if you find this module useful. =head1 SEE ALSO =over 4 =item L What you should be looking at rather than this internal stuff =back =head1 LICENCE Copyright 2006 Adrian Howard, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut