Testing with Test::More
๐งช Testing with Test::More
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($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.
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.
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.
๐ฏ 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.