On Thu Apr 15 09:19:18 2010, KENFOX wrote:
Show quoted text> There's a recurring problem in my company's test code where test methods
> accidentally return from a test and Test::Class assumes they were
> intentionally skipped. It is very easy to skip tests explicitly, so it
> would be beneficial to us to turn off this feature.
See attached for a patch which I believe addresses this issue. It
introduces an option called "fail_if_returned_early" at the class level;
if true, then an early return causes failures instead of skips.
diff -ru Test-Class-0.36/lib/Test/Class.pm Test-Class-0.36-fail-if-returned-early/lib/Test/Class.pm
--- Test-Class-0.36/lib/Test/Class.pm 2010-08-19 14:25:59.000000000 +0100
+++ Test-Class-0.36-fail-if-returned-early/lib/Test/Class.pm 2010-09-20 11:22:36.000000000 +0100
@@ -286,13 +286,19 @@
$skip_reason = "$method died";
$exception = '';
} else {
- $Builder->skip( $skip_reason );
+ if ($self->fail_if_returned_early) {
+ $Builder->ok(0, "(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;
@@ -871,9 +877,25 @@
Startup methods are a special case. 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 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<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";
+ }
+ }
+
=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. The value returned is used as the reason for the tests being skipped.
+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:
@@ -1495,6 +1517,10 @@
See the section on the L</"GENERAL FILTERING OF TESTS"> for more information.
+=item B<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 L<"Returning Early"> and L<"Skipped Tests">.
+
=back
diff -ru Test-Class-0.36/t/runtests_return.t Test-Class-0.36-fail-if-returned-early/t/runtests_return.t
--- Test-Class-0.36/t/runtests_return.t 2010-08-19 14:25:59.000000000 +0100
+++ Test-Class-0.36-fail-if-returned-early/t/runtests_return.t 2010-09-20 10:01:40.000000000 +0100
@@ -13,9 +13,25 @@
ok(-w "/Library", "/Library writable")
};
+package Bar;
+use Test::More;
+use base qw(Test::Class);
+
+sub fail_if_returned_early { 1 }
+
+sub darwin_only : Test {
+ return("darwin only test");# unless $^O eq "darwin";
+ ok(-w "/Library", "/Library writable")
+};
+
package main;
-use Test::Builder::Tester tests => 1;
+use Test::Builder::Tester tests => 2;
test_out("ok 1 # skip darwin only test");
Foo->runtests;
-test_test("early return handled");
+test_test("early return handled (skip)");
+
+test_out("not ok 1 - (returned before plan complete)");
+test_err(qr/.*in Bar->darwin_only.*/s);
+Bar->runtests;
+test_test("early return handled (fail)");