My own test functions with Test Builder level


Behind the scenes both Test::Simple and Test::More use a module called Test::Builder. Actually Test::Builder is doing the hard work of counting test and displaying error messages. Test::More is just the user friendly front end.

Adding the local $Test::Builder::Level = $Test::Builder::Level + 1; to our own test function will tell Test::Builder to go one level further back in the call stack to find the location where the function was called and where the error occurred.


examples/test-perl/t/dice_is_any_fixed.t
use strict;
use warnings;

use MyTools;

use List::MoreUtils qw(any);

use Test::More tests => 8;


for (1..4) {
    my $n = 6;
    my @expected = (1..$n);
    my $value = dice($n);
    is_any($value, \@expected, 'correct number');
}


for (1..4) {
    my $n = 4;
    my @expected = (1..$n);
    my $value = dice($n);
    is_any($value, \@expected, 'correct number');
}


sub is_any {
    my ($actual, $expected, $name) = @_;
    $name ||= '';

    local $Test::Builder::Level = $Test::Builder::Level + 1;
    ok( (any {$_ eq $actual} @$expected), 'correct number')
        or diag "Received: $actual\nExpected:\n" .
            join "", map {"         $_\n"} @$expected;
}

Output:


1..8
not ok 1 - correct number
#   Failed test 'correct number'
#   at t/dice_is_any.t line 16.
# Received: 5.5
# Expected:
#          1
#          2
#          3
#          4
#          5
#          6
ok 2 - correct number
ok 3 - correct number
ok 4 - correct number
ok 5 - correct number
not ok 6 - correct number
#   Failed test 'correct number'
#   at t/dice_is_any.t line 24.
# Received: 1.5
# Expected:
#          1
#          2
#          3
#          4
ok 7 - correct number
ok 8 - correct number
# Looks like you failed 2 tests of 8.