Test::Deep by Fergal Daly provides various function testing data structure is much better way than is_deeply of Test::More. We return to the example examples/perl/lib/MyBugs.pm

examples/perl/t/test_deep.t
use strict;
use warnings;

use Test::More tests => 3;
use Test::Deep;

use lib 'lib';
use MyBugs;

use Data::Dumper;

my $NUMBER = re('^\d+$');

my %expected = (
        bugs     => $NUMBER,
        errors   => $NUMBER,
        failures => $NUMBER,
        warnings => $NUMBER,
    );

#diag Dumper \%a;
for my $i (0..3) {
    my %a = fetch_data_from_bug_tracking_system($i);
    cmp_deeply(\%a, \%expected, 'hash is ok');
}


examples/perl/t/test_deep.out
1..3
ok 1 - hash is ok
ok 2 - hash is ok
not ok 3 - hash is ok
#   Failed test 'hash is ok'
#   at t/test_deep.t line 24.
# Comparing hash keys of $data
# Missing: 'bugs', 'errors'
# Extra: 'bogs', 'erors'
not ok 4 - hash is ok
#   Failed test 'hash is ok'
#   at t/test_deep.t line 24.
# Using Regexp on $data->{"bugs"}
#    got : 'many'
# expect : (?-xism:^\d+$)
# Looks like you planned 3 tests but ran 1 extra.
# Looks like you failed 2 tests of 4 run.
examples/perl/t/bag.t
use strict;
use warnings;

use Test::More tests => 2;
use Test::Deep;


{
    my @expected = (1, 2, 3);
    my @received = (3, 1, 2);
    cmp_bag(\@received, \@expected);
}

{
    my @expected = ([1, 'a'], [2, 'b'], [3, 'c']);
    my @received = ([3, 'c'], [1, 'a'], [2, 'b']);
    cmp_bag(\@received, \@expected);
}