If you really want to make something a habit, find a way to do it
without thinking about it. I like to automate the things I value so I never do
them incorrectly, incompletely, or infrequently. Thus Test::Perl::Critic
allows you to add customizable Perl::Critic tests to your test
suites, so you can ensure that you’ve followed local style.
I’ve been part of the Perl QA group for around five years. In that time, we’ve built dozens of wonderful test modules around a common backend library and a common protocol, evangelized testing and quality to the Perl 5 and Perl 6 developers, spread the expectation and understanding of good testing to CPAN contributors and more, and even built automated systems to check various quality measures of public code.
Tests aren’t the only measure of quality; maintainability for code you expect to maintain is also highly important.
Damian Conway’s Perl Best Practices is a good start for evaluating your coding style and practices. Any maintainability guidelines should start there.
One of the most interesting developments in Perl 5 in recent years is Adam Kennedy’s PPI, a Perl document parser. It can parse most Perl code without actually executing it. This has powerful implications for static code analysis.
Shortly after the advent of PBP and PPI, Jeffrey Ryan Thalhammer created Perl::Critic, an extensible PPI-based static analysis tool. It builds on the recommendations of PBP and adds other metrics to identify source code that varies from local standards.
If you really want to make something a habit, find a way to do it
without thinking about it. I like to automate the things I value so I never do
them incorrectly, incompletely, or infrequently. Thus Test::Perl::Critic
allows you to add customizable Perl::Critic tests to your test
suites, so you can ensure that you’ve followed local style.
Installation
I used the CPAN shell to install the module. Everything went well.
Although I already had Perl::Critic and PPI
installed, both distributions move frequently, so I needed to install new
versions. There were a few other dependencies, including
Perl::Critic::Utils, Test::Object, and
Test::Simple (0.64). The instalation worked flawlessly.
Usage
The default usage is simple. I added the example from the documentation as t/critic.t to my Test::MockObject directory. That’s all it took to get started.
#! perl
use strict;
use warnings;
use Test::Perl::Critic;
all_critic_ok();
That found some violations:
$ perl -Ilib t/critic.t
1..2
not ok 1 - Test::Perl::Critic for "blib/lib/Test/MockObject.pm"
# Failed test 'Test::Perl::Critic for "blib/lib/Test/MockObject.pm"'
# in /usr/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm at line 95.
#
# Perl::Critic found these violations in "blib/lib/Test/MockObject.pm":
# Stricture disabled at line 126, column 3. See page 429 of PBP. (Severity: 5)
# Stricture disabled at line 301, column 3. See page 429 of PBP. (Severity: 5)
# Stricture disabled at line 314, column 3. See page 429 of PBP. (Severity: 5)
not ok 2 - Test::Perl::Critic for "blib/lib/Test/MockObject/Extends.pm"
# Failed test 'Test::Perl::Critic for "blib/lib/Test/MockObject/Extends.pm"'
# in /usr/lib/perl5/site_perl/5.8.8/Test/Perl/Critic.pm at line 95.
#
# Perl::Critic found these violations in "blib/lib/Test/MockObject/Extends.pm":
# Stricture disabled at line 54, column 2. See page 429 of PBP. (Severity: 5)
# Stricture disabled at line 71, column 3. See page 429 of PBP. (Severity: 5)
# Stricture disabled at line 127, column 5. See page 429 of PBP. (Severity: 5)
# Stricture disabled at line 150, column 3. See page 429 of PBP. (Severity: 5)
# Stricture disabled at line 163, column 2. See page 429 of PBP. (Severity: 5)
# Looks like you failed 2 tests of 2.
There are six places in the distribution where I disabled strictures. This is okay; it’s doing complex things. Of course, I wanted to browse the code to see if there were any errors. This exercise showed me one spot where I disabled symbolic reference checking in far too wide a scope. I fixed that potential bug. How nice!
Customizing the Behavior
Unfortunately, all of these symbolic references are necessary for the
modules to work properly. If I want to keep these tests, I would need some
mechanism to allow their use but still pass the check.
Test::Perl::Critic uses the .perlcriticrc file, as
documented in Perl::Critic. I added an empty file in
t/perlcriticrc and added a line to the test file:
use Test::Perl::Critic -profile => 't/perlcriticrc';
The configuration file needs something in it, and to prevent these
particular policies from running, I need to know the name of the policy
being violated. Test::Perl::Critic supports a
-verbose flag to change its output message. I chose to pass a
format string to show only the name of the failed policy:
use Test::Perl::Critic -verbose => '%p';
I recommend this only for debugging; it changes the entire debugging message. Another option was verbosity level 9, but I wanted only the name of the policy to disable. I could have come up with my own custom format string (and that’s probably the right answer), but this worked for me.
My resulting t/perlcriticrc file is:
[-TestingAndDebugging::ProhibitNoStrict]
Unfortunately, my tests continued to fail until I noticed that I had
used policy in the test file instead of profile.
Oops. Beware.
There are other customizations too. For example, the default seems to
report only failed policies at severity 5 (the least severe). I was curious
about how the code looked at a lower severity, so I added to the
use line:
-severity => 3;
That gave many more warnings. Unfortunately, I found no easy way to set
the default severity in my t/perlcriticrc file, but that would
have been useful. (I think this is a shortcoming — or at least a
deliberate design decision — of Perl::Critic instead of the
test module.)
Conclusions
I recommend Test::Perl::Critic, especially if you’ve
already decided which policies you do and do not support. If you haven’t
discussed that yet with your team, the default severity of 5 (again, the
least severe level) is a decent choice.
This module made the right choices. Adding a separate test and policy file to each distribution may seem like busy work, but it allows you to change the severity and rules per project. Using a global .perlcriticrc file would be a mistake. Not only can you improve the compliance of separate projects individually as necessary, but I have some distributions that use some constructs very deliberately but not others. Distributing a policy file (with the appropriate severity) with each distribution helps prevent nasty failures elsewhere.
One question might arise. If you distribute your code, should you distribute these test files? I agree with the authors; it’s inappropriate. These are developer-side tests and represent little value for users. They represent tremendous potential value for authors, however. It’s worth experimenting with what this reveals about your code.

I would also like to point to the many Perl::Critic add-on modules, where dozens of CPAN authors have created their own sets of policies, using the flexible Perl::Critic framework.
Actually, there's only one author that's done it, but they're some fine, fine policies, if I do say so myself. I point you to Perl::Critic::Bangs (http://search.cpan.org/dist/Perl-Critic-Bangs/), with policies for vague variable names, commented-out code, and use of the dreaded no_plan in tests.
I looked at the Perl::Critic doco and it shows right there how to put the severity level in the perlcriticrc:
[Perl::Critic::Policy::Category::PolicyName]
severity = 1
arg1 = value1
arg2 = value2
HTH
Bob
Bob, that changes only the severity for that specific policy, not the default severity level of the report. I wanted the latter.
Great article! Note that level 5 is the highest severity, not the lowest. So by default, Perl::Critic only reports the most egregious errors.
As you pointed out, this is the intended mechanism for setting the reporing threshold. I can see the virtue of setting this in the .perlcriticrc file. We'll consider that for a future release.
I took the 'default-all-on' approach then changed thing I didn't agree with in my rc. That way, when new policies come out, they're automatically run, and I must make decisions on whether I agree or disagree with them. This seemed safer than tweaking the levels of all of the policies in the rc.
Test::Perl::Critic->import(
-profile => 't/style_perl_critic.rc',
-severity => 1,
-format => "%m at line %l, column %c: %p Severity %s\n\t%r"
);
Did you consider putting a "no critic" and "use critic" comment-directives around the offending lines to indicate a conscious non-compliance? That seems to make perlcritic do what you want, but it seems to be distributing perlcritc pieces when you have decided not to.
Michael, that's a good suggestion. I considered it, but in this case I prefer to leave that information outside the source code. If there were a competing suite of tools, it could be confusing to have multiple analyzer directives in the code.