Search code examples
perltestingtap

Using functions in TAP Harness instead of test files


Here is my current test harness using TAP :

use TAP::Harness;
my $harness = TAP::Harness->new();
$harness->runtests(['sequential.t']);

I would like to avoid using test files and call directly a Perl function instead. Something like :

my %args = (
  exec => run_all_tests(),
);
$harness->runtests();

Solution

  • The main problem is that all modern test modules use Test::Builder under the hood.
    Test::Builder itself assumes that you are only ever going to have one set of tests in a file.
    So we need to reset the singleton for each set of tests (Test::More->builder->reset).

    use strict;
    use warnings;
    
    use TAP::Harness;
    use Test::More;
    
    my %tests = (
      a => sub{
        plan tests => 4;
        ok 5==5, '5 == 5';
        is 5, "5", 'is 5, 5';
        like 5, qr'^\d$', '5 =~ /^\d$/';
        is 5, 4, 'is 5, 4';
      },
      b => sub{
        plan tests => 3;
        ok !0;
        ok !0;
        ok !0;
      },
      c => sub{
        plan 'no_plan';
        ok !0;
        done_testing;
      },
      d => sub{
        ok !0;
        done_testing;
      },
    );
    
    sub runner{
      my($harness,$test) = @_;
    
      my $builder = Test::More->builder;
    
      # reset the Test::Builder object for every "file"
      $builder->reset;
      $builder->{Indent} = ''; # may not be needed
    
      # collect the output into $out
      $builder->output(\my($out));     # STDOUT
      $builder->failure_output(\$out); # STDERR
      $builder->todo_output(\$out);    # STDOUT
    
      # run the test
      $tests{$test}->();
    
      # the output ( needs at least one newline )
      return $out;
    }
    
    my $harness = TAP::Harness->new(
      {
        exec => \&runner,
        verbosity => 1,
      }
    );
    
    $harness->runtests(sort keys %tests);
    
    a .. 
    1..4
    ok 1 - 5 == 5
    ok 2 - is 5, 5
    ok 3 - 5 =~ /^\d$/
    not ok 4 - is 5, 4
    
    #   Failed test 'is 5, 4'
    #   at test.pl line 13.
    #          got: '5'
    #     expected: '4'
    Failed 1/4 subtests 
    b .. 
    1..3
    ok 1
    ok 2
    ok 3
    ok
    c .. 
    ok 1
    1..1
    ok
    d .. 
    ok 1
    1..1
    ok
    
    Test Summary Report
    -------------------
    a (Wstat: 0 Tests: 4 Failed: 1)
      Failed test:  4
    Files=4, Tests=9,  0 wallclock secs ( 0.02 usr +  0.00 sys =  0.02 CPU)
    Result: FAIL