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;