Ovid
2012-12-12 17:51:27 UTC
Hi all,
People keep asking me how to properly integrate Moose with Test::Class. I know about Test::Able and some alternatives, but I *generally* like Test::Class's interface (or maybe I'm just in a comfort zone). So I wrote my own Test::Class::Moose (it does not use Test::Class) and it uses subtests all the way down.
Every test class is one test. Every test method is a subtest in the test class. Every test in a test method is, well, one test in a test method. Here's a simple test class which, in turn, inherits from another test class (you get all of the functions from Test::Most along with Moose helper functions, if desired):
package TestsFor::Basic::Subclass;
use Test::Class::Moose parent => 'TestsFor::Basic';
sub test_startup {
my $test = shift;
$test->next::method;
# more startup here, but tests are not allowed
}
sub test_me {
my $test = shift;
my $class = $test->this_class;
ok 1, "I overrode my parent! ($class)";
}
before 'test_this_baby' => sub {
my $test = shift;
my $class = $test->this_class;
pass "This should run before my parent method ($class)";
};
sub this_should_not_run {
fail "We should never see this test";
}
sub test_this_should_be_run {
for ( 1 .. 5 ) {
pass "This is test number $_ in this method";
}
}
1;
Note that attributes are not required on the test methods. Methods which start with "test_" are considered test methods (you can override this behavior, of course). That includes the test control methods of test_startup(), test_setup(), and so on.
You should be able to consume roles or use the rest of Moose any way you think you should.
Here's how we load and run tests:
use Test::Class::Moose::Load qw(t/lib);
Test::Class::Moose->new({
# timing on a class and method level
show_timing => 0,
# how many classes, methods and tests
statistics => 1,
})->runtests;
My main concern is that the nested subtests will annoy people:
#
# Executing tests for TestsFor::Basic::Subclass
#
# TestsFor::Basic::Subclass->test_me()
ok 1 - I overrode my parent! (TestsFor::Basic::Subclass)
1..1
ok 1 - test_me
# TestsFor::Basic::Subclass->test_this_baby()
ok 1 - This should run before my parent method (TestsFor::Basic::Subclass)
ok 2 - whee! (TestsFor::Basic::Subclass)
1..2
ok 2 - test_this_baby
# TestsFor::Basic::Subclass->test_this_should_be_run()
ok 1 - This is test number 1 in this method
ok 2 - This is test number 2 in this method
ok 3 - This is test number 3 in this method
ok 4 - This is test number 4 in this method
ok 5 - This is test number 5 in this method
1..5
ok 3 - test_this_should_be_run
1..3
ok 1 - TestsFor::Basic::Subclass
#
# Executing tests for TestsFor::Basic
#
# TestsFor::Basic->test_me()
ok 1 - test_me() ran (TestsFor::Basic)
ok 2 - this is another test (TestsFor::Basic)
1..2
ok 1 - test_me
# TestsFor::Basic->test_this_baby()
ok 1 - whee! (TestsFor::Basic)
1..1
ok 2 - test_this_baby
1..2
ok 2 - TestsFor::Basic
1..2
# Test classes: 2
# Test methods: 5
# Total tests run: 11
ok
All tests successful.
Files=1, Tests=2, 2 wallclock secs
Result: PASS
So, does this look useful for folks? Is there anything you would change? (It's trivial to assert plans for classes and the entire test suite rather than rely on done_testing(), but I haven't done that yet).
Cheers,
Ovid
--
Twitter - http://twitter.com/OvidPerl/
Buy my book - http://bit.ly/beginning_perl
Buy my other book - http://www.oreilly.com/catalog/perlhks/
Live and work overseas - http://www.overseas-exile.com/
People keep asking me how to properly integrate Moose with Test::Class. I know about Test::Able and some alternatives, but I *generally* like Test::Class's interface (or maybe I'm just in a comfort zone). So I wrote my own Test::Class::Moose (it does not use Test::Class) and it uses subtests all the way down.
Every test class is one test. Every test method is a subtest in the test class. Every test in a test method is, well, one test in a test method. Here's a simple test class which, in turn, inherits from another test class (you get all of the functions from Test::Most along with Moose helper functions, if desired):
package TestsFor::Basic::Subclass;
use Test::Class::Moose parent => 'TestsFor::Basic';
sub test_startup {
my $test = shift;
$test->next::method;
# more startup here, but tests are not allowed
}
sub test_me {
my $test = shift;
my $class = $test->this_class;
ok 1, "I overrode my parent! ($class)";
}
before 'test_this_baby' => sub {
my $test = shift;
my $class = $test->this_class;
pass "This should run before my parent method ($class)";
};
sub this_should_not_run {
fail "We should never see this test";
}
sub test_this_should_be_run {
for ( 1 .. 5 ) {
pass "This is test number $_ in this method";
}
}
1;
Note that attributes are not required on the test methods. Methods which start with "test_" are considered test methods (you can override this behavior, of course). That includes the test control methods of test_startup(), test_setup(), and so on.
You should be able to consume roles or use the rest of Moose any way you think you should.
Here's how we load and run tests:
use Test::Class::Moose::Load qw(t/lib);
Test::Class::Moose->new({
# timing on a class and method level
show_timing => 0,
# how many classes, methods and tests
statistics => 1,
})->runtests;
My main concern is that the nested subtests will annoy people:
#
# Executing tests for TestsFor::Basic::Subclass
#
# TestsFor::Basic::Subclass->test_me()
ok 1 - I overrode my parent! (TestsFor::Basic::Subclass)
1..1
ok 1 - test_me
# TestsFor::Basic::Subclass->test_this_baby()
ok 1 - This should run before my parent method (TestsFor::Basic::Subclass)
ok 2 - whee! (TestsFor::Basic::Subclass)
1..2
ok 2 - test_this_baby
# TestsFor::Basic::Subclass->test_this_should_be_run()
ok 1 - This is test number 1 in this method
ok 2 - This is test number 2 in this method
ok 3 - This is test number 3 in this method
ok 4 - This is test number 4 in this method
ok 5 - This is test number 5 in this method
1..5
ok 3 - test_this_should_be_run
1..3
ok 1 - TestsFor::Basic::Subclass
#
# Executing tests for TestsFor::Basic
#
# TestsFor::Basic->test_me()
ok 1 - test_me() ran (TestsFor::Basic)
ok 2 - this is another test (TestsFor::Basic)
1..2
ok 1 - test_me
# TestsFor::Basic->test_this_baby()
ok 1 - whee! (TestsFor::Basic)
1..1
ok 2 - test_this_baby
1..2
ok 2 - TestsFor::Basic
1..2
# Test classes: 2
# Test methods: 5
# Total tests run: 11
ok
All tests successful.
Files=1, Tests=2, 2 wallclock secs
Result: PASS
So, does this look useful for folks? Is there anything you would change? (It's trivial to assert plans for classes and the entire test suite rather than rely on done_testing(), but I haven't done that yet).
Cheers,
Ovid
--
Twitter - http://twitter.com/OvidPerl/
Buy my book - http://bit.ly/beginning_perl
Buy my other book - http://www.oreilly.com/catalog/perlhks/
Live and work overseas - http://www.overseas-exile.com/