How to use Test::Deep for complex data structure comparison?
Question
How to use Test::Deep for complex data structure comparison?
Test::Deep is a powerful Perl testing module designed for comparing complex data structures with precision and flexibility. Unlike simple equality checks, Test::Deep provides a rich set of tools to deeply inspect nested arrays, hashes, objects, and even partial matches or patterns.
Why Use Test::Deep?
When testing complex data structures—like nested hashes of arrays or objects—using simple equality operators (like eq or ==) is often insufficient or cumbersome. Test::Deep lets you:
- Compare deep nested data structures for equivalence.
- Make partial comparisons (check only certain keys or elements).
- Use flexible comparisons (ignore order, use regex matches, check object classes).
It abstracts away the typical Perl pain points involving sigils and context in complex structures by offering a readable domain-specific language (DSL) to describe expected data.
Basic Usage
First, ensure Test::Deep is installed. It’s a core Perl testing module as of Perl 5.16 but might need to be installed separately on older versions. The typical import is:
use Test::Deep 'cmp_deeply';
The main function is cmp_deeply($got, $expected, $test_name), which performs a deep comparison of two data structures and integrates well with standard test harnesses.
Example: Comparing Nested Data Structures
Here’s a runnable example showing how to compare complex nested data structures using Test::Deep:
use strict;
use warnings;
use Test::Deep 'cmp_deeply';
# Two complex nested data structures (hashes of arrays, etc.)
my $data1 = {
users => [
{ id => 1, name => 'Alice', roles => ['admin', 'user'] },
{ id => 2, name => 'Bob', roles => ['user'] },
],
meta => {
total_users => 2,
active => 1,
},
};
my $data2 = {
users => [
{ id => 1, name => 'Alice', roles => ['admin', 'user'] },
{ id => 2, name => 'Bob', roles => ['user'] },
],
meta => {
total_users => 2,
active => 1,
},
};
# Deep comparison succeeds here
cmp_deeply($data1, $data2, "Complex data structures match");
# Now an example with a difference
my $data3 = {
users => [
{ id => 1, name => 'Alice', roles => ['user'] }, # missing 'admin' role
{ id => 2, name => 'Bob', roles => ['user'] },
],
meta => {
total_users => 2,
active => 1,
},
};
cmp_deeply($data1, $data3, "Detects role array difference");
Running this script prints test output indicating matches or mismatches:
Complex data structures matchpasses because$data1and$data2are identical.Detects role array differencefails because$data3has fewer roles for Alice.
Common Features & Gotchas
- Understanding sigils:
@{...}and%{...}are often used internally, butTest::Deepworks on references directly, so no extra dereferencing is needed beyond normal Perl structure references. - Order Sensitivity: By default, array order matters. Use
bag(collection ignoring order) orunorderedwrappers fromTest::Deepif order can vary. - Partial Matching:
Test::Deepcan test that certain keys exist and have expected values, ignoring other keys by using helpers likesuperhashof. - Objects:
Test::Deepcan compare objects by class or by their internals with helpers likeobj. - Context: The
cmp_deeplyfunction returns a boolean test result, useful inTest::Moreor standalone scripts.
Version Notes
Test::Deep works well with Perl 5.8 and above, but being a CPAN module it also has updates introducing features in newer versions that you can find on CPAN. For basic usage, no special version is needed.
Summary
Test::Deep is highly recommended when you want robust, flexible comparison of nested or complex data structures in your Perl tests. It embraces Perl’s TMTOWTDI (There’s More Than One Way To Do It) philosophy by providing multiple matchers (deep equality, partial match, regex, unordered arrays) to suit your testing needs.
Using cmp_deeply lets you write clear, maintainable tests that show exactly where data structures differ, improving debugging and confidence in your Perl code.
Verified Code
Executed in a sandbox to capture real output. • v5.34.1 • 95ms
(empty)(empty)Was this helpful?
Related Questions
- How to test Mojolicious applications in Perl?
- How to test HTTP responses with Test::WWW::Mechanize in Perl?
- How to use prove command to run Perl tests?
- How to test database code with Test::mysqld in Perl?
- How to use Test::Fatal for exception testing in Perl?
- How to test regular expressions with like in Perl Test::More?