Test::Class + Moose?
I recently wrote about finding duplicate code in Perl and I've just uploaded Code::CutNPaste to the CPAN. Hopefully folks will find it useful.
However, what's not yet on the CPAN is Test::Class::Moose. People have asked me repeatedly how to mix the two, so I whipped up a quick alpha.
This isn't the first time this has been done. Test::Sweet may not have gotten much traction because of its dependency on Devel::Declare. Test::Able looks very interesting, but for some reason, whenever I point people at it, they ignore it. I don't know why that is. Maybe the declarative interface?
So I said "screw it" and wrote my own. Here's one of the test classes from the (too small) test suite:
package TestsFor::Some::Class::Subclass;
use Test::Class::Moose extends => 'TestsFor::Some::Class';
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 {
my $test = shift;
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 the Moose-y goodness in there.
Test methods start with test_
. Don't like that? Override the get_test_methods()
method. Need roles? Just use Moose::Role
. Need attributes? Just use normal Moose
attributes.
One thing people may not like is that it's subtests all the way down (and note the diagnostic summary at the end):
1..2
#
# Executing tests for TestsFor::Basic::Subclass
#
1..3
# 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
ok 1 - TestsFor::Basic::Subclass
#
# Executing tests for TestsFor::Basic
#
1..2
# 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
ok 2 - TestsFor::Basic
# Test classes: 2
# Test methods: 5
# Total tests run: 11
ok
All tests successful.
Files=1, Tests=2, 2 wallclock secs ( 0.03 usr 0.00 sys + 0.27 cusr 0.01 csys = 0.31 CPU)
Result: PASS
Making everything subtests made this trivial to write.
Also, you don't need to declare plans. Anywhere. There's a top-level plan which is the number of test classes. Test::Class::Moose
declares that for you. There's a per-class plan for the number of test methods. Test::Class::Moose
declares that for you, too. Each test method relies on an implicit done_testing()
. This isn't optimal, but again, it made a lot of headache go away. You could declare a plan for each test method, but if you overrode it in a subclass and tried to call your parent method, plans would get confused.
Give it a whirl and let me know what you think.
Any thoughts on Test::Routine?
Is Test::Class::Moose for situations where compatibility with Test::Class is important?
arunbear, to be honest, I wasn't quite sure what the benefit of Test::Routine is. For example, I don't see how it lets you inherit tests. However, Ricardo's a sharp enough developer that I'd be foolish to dismiss it without better understanding it. Its main benefit seems to be that you can use roles with tests, but there's no example of using roles in it (or is there and I missed it in my skim?)
With Test::Class::Moose, you get classes and roles and tests. There's no new interface to learn and it's not doing anything funky. Anything you can do with classes and roles you can do with Test::Class::Moose. Because there's no "magic", it's pretty straightforward (assuming you already know Test::Class).
The examples in Test::Routine::Manual::Demo all use roles. In fact all tests defined with Test::Routine live in roles, and it can automatically assemble such roles into a test class.
But it doesn't stop you from manually assembling the roles into a test class, or sub-classing such a class if needed (though such assembly would be done using the usual Moose constructs).