Testing with Test::More

Perl Intermediate/Advanced
Course 2 ยท Chapter 8 ยท Testing with Test::More

๐Ÿงช Testing with Test::More

Perl has one of the oldest, most established testing cultures in programming โ€” TAP (Test Anything Protocol), the output format Test::More produces, originated in Perl and was later adopted as a language-agnostic standard used by testing tools well beyond Perl itself. This chapter covers writing and running real tests.

โœ… The Basic Assertions

use Test::More;

ok(1 + 1 == 2, 'basic math works');          # true/false โ€” the most basic assertion
is(2 + 2, 4, 'addition is correct');          # equality โ€” reports BOTH values on failure
isnt(2 + 2, 5, 'addition is not wrong');     # inequality
like("Hello World", qr/World/, 'contains World');   # regex match โ€” reuses Chapter 1's m// and qr//

is() is preferred over ok($got == $expected, ...) for equality checks specifically because a failure reports both the actual and expected values automatically โ€” genuinely more useful for diagnosing what went wrong than a bare pass/fail from ok alone.

๐Ÿ“ A First Test File

# t/basic.t
use strict;
use warnings;
use Test::More;

is(1 + 1, 2, 'one plus one is two');
ok("perl" eq "perl", 'strings match');

done_testing();   # modern style โ€” no need to declare a plan count up front

Test files conventionally live in a t/ directory and end in .t. done_testing(); at the end is the modern convention, replacing the older style of declaring use Test::More tests => 5; and having to keep that count manually in sync with the actual number of assertions.

โ–ถ๏ธ Running Tests with prove

prove t/basic.t     # run one test file
prove -r t/          # recursively run every .t file in the t/ directory
t/basic.t .. ok
All tests successful.
Files=1, Tests=2,  0 wallclock secs

prove (installed alongside Perl itself) is the standard test runner โ€” it executes every matched .t file and reports a clean pass/fail summary.

๐Ÿ—๏ธ Testing Data Structures

my $got      = { name => "Ada", age => 28 };
my $expected = { name => "Ada", age => 28 };

is_deeply($got, $expected, 'hashref contents match');   # PASSES โ€” compares contents, not identity
โš  is() on References Checks Identity, Not Contents

is($got, $expected, ...) on two references โ€” even two hashrefs holding identical data โ€” compares whether they're the exact same reference in memory (Course 1, Chapter 9's reference-vs-value distinction), not whether their contents match. Two separately-built hashrefs with identical keys and values will fail a plain is() check. is_deeply() is the correct tool for comparing the actual contents of nested arrays/hashes, recursively.

๐Ÿ”ง A Worked Example โ€” Testing a Real Subroutine

# t/multiplier.t
use strict;
use warnings;
use Test::More;

sub make_multiplier {   # reused from Chapter 7
    my ($factor) = @_;
    return sub { my ($n) = @_; return $n * $factor; };
}

my $double = make_multiplier(2);

is($double->(5), 10, 'double(5) is 10');
is($double->(0), 0, 'double(0) is 0');
like("Result: " . $double->(3), qr/\d+/, 'result contains a number');

done_testing();

This exercises a closure (Chapter 7) directly through Test::More's assertions โ€” is() for the expected numeric results, like() confirming the output's shape via regex rather than an exact string match.

TAP: Perl's Testing Format, Adopted Widely

TAP (Test Anything Protocol) โ€” the simple, line-based pass/fail output Test::More produces โ€” originated in Perl's testing culture and was later formalized as a language-agnostic standard, with TAP producers and consumers built for many other languages beyond Perl. This is a genuine parallel to CPAN's own historical head start (Chapter 5): Perl's testing tooling matured early enough to influence testing practices well outside the language itself, much like PCRE's regex engine did.

ok / is / isnt / like

The core assertions โ€” is() for equality reports both values on failure.

done_testing()

Modern style โ€” no upfront test-count plan to keep in sync.

prove

The standard test runner โ€” prove -r t/ runs every test file.

is_deeply

Compares reference contents recursively โ€” is() alone only checks identity.

๐Ÿ’ป Coding Challenges

Challenge 1: A Basic Test File

Write a test file t/strings.t with at least 3 assertions covering string concatenation, a regex match with like, and one intentionally-failing assertion (to see what a failure looks like) โ€” then remove the failing one and confirm all tests pass with prove.

โ†’ Solution

Challenge 2: Test a Subroutine From Course 1

Write a test file testing Course 1, Chapter 7's power subroutine (base and optional exponent, defaulting to 2) with at least 3 is() assertions covering both the default and an explicit exponent.

โ†’ Solution

Challenge 3: is vs is_deeply

Given two separately-built arrayrefs both containing (1, 2, 3), write one assertion using is() (predict and note that it fails) and one using is_deeply() (predict and note that it passes), and explain in one sentence why they disagree.

โ†’ Solution

๐ŸŽฏ What's Next

Final chapter: Perl One-Liners & Practical Text Processing โ€” perl -e/-pe/-ne, closing the loop back to the Bash/sed/awk cluster.