Perl Advent Calendar 2007-12-04

You don't get a belly like this drinking skim milk

by Josh McAdams

Santa is a big ball of cheer, but he didn't get so big by going light on the treats that all of the children set out for him on Christmas Eve. To help Santa check up on the snacks that are left for him, we'll use Test::Differences to highlight the differences in the complex data structures that Santa uses to keep track of the treats he expects to receive and those that his elves report to him while scouting the field.

Of course, Santa is not the only one checking his list on Christmas. All of the children need a way to compare the multiline scalar list of toys they wanted to the scalar list of toys they received.

Test::Differences is a module that picks up where Test::More::is_deeply leaves off. It can compare complex data structures and multiline strings, showing the data that was expected and what was gotten side-by-side for easy review. If you're worried about too much output, don't. You can set the amount of context shown around the differences so that the entire data structures that you diff don't get printed.

mod4.pl

   1 use Test::More tests => 1;
   2 use Test::Differences;
   3 
   4 my $expected =
   5   { cookies => [qw(oatmeal lemondrop)], milk => [qw(whole chocolate)] };
   6 my $got = { cookies => [qw(oatmeal lemondrop)], milk => [qw(skim chocolate)] };
   7 
   8 eq_or_diff $got, $expected, "Santa's treats";
   9 
  10 $expected = "Baseball bat\nComic books\niPod\n";
  11 $got      = "Baseball bat\nComic books\nZune\n";
  12 
  13 eq_or_diff $got, $expected, 'x-mas list';
1..1
not ok 1 - Santa's treats
#   Failed test 'Santa's treats'
#   at mod4.pl line 11.
# +----+-----------------+-----------------+
# | Elt|Got              |Expected         |
# +----+-----------------+-----------------+
# |   0|{                |{                |
# |   1|  cookies => [   |  cookies => [   |
# |   2|    'oatmeal',   |    'oatmeal',   |
# |   3|    'lemondrop'  |    'lemondrop'  |
# |   4|  ],             |  ],             |
# |   5|  milk => [      |  milk => [      |
# *   6|    'skim',      |    'whole',     *
# |   7|    'chocolate'  |    'chocolate'  |
# |   8|  ]              |  ]              |
# |   9|}                |}                |
# +----+-----------------+-----------------+
not ok 2 - x-mas list
#   Failed test 'x-mas list'
#   at mod4.pl line 16.
# +---+--------------+--------------+
# | Ln|Got           |Expected      |
# +---+--------------+--------------+
# |  1|Baseball bat  |Baseball bat  |
# |  2|Comic books   |Comic books   |
# *  3|Zune          |iPod          *
# +---+--------------+--------------+
# Looks like you planned 1 test but ran 1 extra.
# Looks like you failed 2 tests of 2 run.

As you can see, Test::Differences gives you quite a bit more power and information than Test::More::is_deeply does, yet it works on the same Test::Builder framework, so it works flawlessly with all of the standard Perl testing modules that you are used to.