testing intermediate

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 match passes because $data1 and $data2 are identical.
  • Detects role array difference fails because $data3 has fewer roles for Alice.

Common Features & Gotchas

  • Understanding sigils: @{...} and %{...} are often used internally, but Test::Deep works 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) or unordered wrappers from Test::Deep if order can vary.
  • Partial Matching: Test::Deep can test that certain keys exist and have expected values, ignoring other keys by using helpers like superhashof.
  • Objects: Test::Deep can compare objects by class or by their internals with helpers like obj.
  • Context: The cmp_deeply function returns a boolean test result, useful in Test::More or 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

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
(empty)
STDERR
(empty)

Was this helpful?

Related Questions