Let’s assume for the moment that you’re writing a Perl module or application. You’d like to maintain some level of software quality (or kwalitee), so you’re writing a suite of test scripts. Whether you’re writing them first (good for you for practicing test-driven development!) or the application code is already there, you’ll probably be reaching for Test::Simple, Test::More, or one of the Test2::Suite bundles. With the latter two you’re immediately confronted with a choice: do you count up the number of tests into a plan, or do you forsake that in favor of leaving a
done_testing() call at the end of your test script(s)?
There are good arguments for both approaches. When you first start, you probably have no idea how many tests your scripts will contain. After all, a test script can be a useful tool for designing a module’s interface by writing example code that will use it. Your exploratory code would be written as if the module or application was already done, testing it in the way you’d like it to work. Not declaring a plan makes perfect sense in this case; just put
done_testing() at the end and get back to defining your tests.
You don’t have that option when using Test::Simple, of course — it’s so basic it only has one function (
ok()), and you have to pre-declare how many tests you plan to run when
useing the module, like so:
use Test::Simple tests => 23;
Test::More also supports this form of plan, or you can opt to use its
plan function to state the number of tests in your script or
subtest. With Test2 you have to use
plan. Either way, the plan acts as a sort of meta-test, making sure that you executed exactly what you intended: no more, no less. While there are situations where it’s not possible to predict how many times a given set of tests should run, I would highly suggest that in all other cases you should “clean up” your tests and declare a plan. Later on, if you add or remove tests you’ll immediately be aware that something has changed and it’s time to tally up a new plan.
What about other Perl testing frameworks? They can use plans, too. Here are two examples:
- Test::Class declares its plans as part of the method’s Test attribute, and uses helper methods called
fail_if_returned_lateto indicate that an unfollowed plan should trigger failure.
- Test::Class::Moose says “no plans needed” but also supports declaring plans either in an attribute or via a method call.
Thoughts? Does declaring a test plan make writing tests too inflexible? Does not having a plan encourage bad behavior? Tell me what you think in the comments below.