Precision Testing for Modern Perl
In a previous entry I discussed some of my favourite CPAN modules for testing Perl code.
I got to thinking... there are all these little frameworks on the CPAN like GID, and Modern::Perl, and Defaults::Modern, and Bubblegum which are basically little shims to load collections of "best practices" modules in a single line. For example:
use Modern::Perl;
is basically a shortcut for:
use IO::File qw(); use IO::Handle qw(); use strict; use warnings; use feature qw( :5.12 ); use mro qw( c3 );
So why not do the same for test suites? Why not create a module that loads Test::More, and Test::Fatal, and Test::Warnings, and so on for me?
I know what you're thinking... Test::Most already exists. Test::Most is a good module, but it's been around a few years, and it shows. For example, it uses Test::Exception which is generally thought problematic compared to the newer Test::Fatal; similarly Test::Most uses Test::Warn where Test::Warnings might be a better choice. It's unlikely Ovid could ever change this situation without breaking a substantial number of the over 300 distributions that depend on Test::Most.
So I went and wrote Test::Modern which combines Test::More, Test::Fatal, Test::Warnings, and more. It automatically imports strict and warnings for you, and enables Test::Warnings' had_no_warnings
feature so that any unexpected warnings will cause your tests to fail. It provides the ability to mark test scripts as being author, release, or extended tests, and skip them based on the presence or absence of environment variables (like Test::DescribeMe), or skip tests based on missing dependencies (like Test::Requires).
Because much modern Perl code is quite object-oriented, it provides an object_ok
function combining Test::More's isa_ok
and can_ok
, a Test::Moose-inspired does_ok
, a Test::API-powered class_api_ok
, and a Test::CleanNamespaces-cribbed namespaces_clean
.
Is it likely to be everything you need to test every project in one module? No. But of course using Test::Modern doesn't stop you from using other test modules too!
use Test::Modern; use Test::URI; use MyApp::Person; object_ok( MyApp::Person->new_from_database(id => 42), isa => [qw/ MyApp::Person Moose::Object /], does => [qw/ MyApp::Role::Contact /], can => [qw/ id name email website /], clean => 1, more => sub { my $object = shift; is( $object->name, "Bob" ); uri_scheme_ok( $object->website, 'http' ); }, ); done_testing;
How will test::modern stay modern and not become aged like test::most? Perhaps a year import parameter like modern::perl to allow improvements/changes in future or something similar?
It will eventually become aged. Then I (or someone) will have to write Test::Postmodern. Hopefully that won't be necessary for a few years.
Hopefully Test::Postmodern will not be confused as a module for testing Moose, since Moose is postmodern.
Except so is Perl itself…
Test::CleanNamespaces is back in active development and its underlying implementation is getting fixed up quite a lot, so it would probably be better to call into its version of clean_namespaces rather than copying its guts.