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.

3 Comments

Any thoughts on Test::Routine?

Is Test::Class::Moose for situations where compatibility with Test::Class is important?

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).

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/