如何使用 Test::more 忽略 perl 中的 TAP 结果?

问题描述

我想利用这个库来漂亮地打印我的测试 Test::Differences; 的差异,但我不想在我的计划中计算它,因为它只是在我的用例中用于调试。>

所以我创建了这个问题的一个最小示例来重现这个问题,我知道这样做不是“正确的”,但是很好地说明了这个问题。

use strict;
use warnings;
use utf8::all;
use open ':std',':encoding(UTF-8)';

use Test::Differences;
use Test::Deep::NoTest qw(cmp_details deep_diag);
use Test::More tests => 2;
use JSON;

my $context = 1;
my $extracted_ref = {
    a => '1',b => '2',c => '3',d => '4',};
my $reference_ref = {
    a => '1',b => '3',};

my ($is_compare_ok,$stack) = cmp_details($extracted_ref,$reference_ref);
my $json_reference = JSON->new->canonical->encode($reference_ref);
my $json_extracted = JSON->new->canonical->encode($extracted_ref);

ok(1);
if ($is_compare_ok){
    ok(1);
    return 1;                               
}else{                                  
    ok(0);
    eq_or_diff($reference_ref,$extracted_ref,"Error in '$0'",{context=>$context}); # <- I don't want to count this
    return 0;
}

我希望在脚本结束时执行测试,在此过程中完成的两个 ok。但是函数 eq_or_diff 向 TAP 会话添加一个新测试,因此脚本以执行 3 个测试结束,因此 done_testing() 期望 2 但得到 3

这是一个最小的例子,但通常我有一个主脚本:

main.t

use Test::More tests => 2;
...
ok(some_function_in_other_file_or_library(),"name_of_the_test");
...

lib.pm

...
sub some_function_in_other_file_or_library{
...
   eq_or_diff(...)
   return $bool;
}
...

我提到这一点是因为我尝试使用 substest 并且我也无法使它工作,而且我现在主要不必知道 lib 中发生的事情,否则我认为我可以只使用 {{1 }}:

done_testing($planned_tests+1)

lib.pm

总结:我如何制作类似于:

use Test::More tests qw/subtest/;
subtest 'An example subtest' => sub {
    plan tests => 1;
 
    eq_or_diff(...)
};

解决方法

Test::Differences 和朋友们真的为你做了两件事,然后通过将它与测试框架紧密耦合来使其复杂化。这不是什么大麻烦,因为它实际上只是包装了其他模块中可以直接使用的东西。

首先,它通过设置各种参数,例如Data::Dumper,使用SortKeys输出可预测的序列化。其次,它使用 Text::Diff 来比较这些转储的行。

所以,就自己做吧。这是第一部分,它只返回表示转储的单个字符串,适用于字符串比较以查看它们是否相等:

sub dump_it {
    my( $arg ) = @_;
    local $Data::Dumper::Deparse   = 1;
    local $Data::Dumper::Indent    = 1;
    local $Data::Dumper::Purity    = 0;
    local $Data::Dumper::Terse     = 1;
    local $Data::Dumper::Deepcopy  = 1;
    local $Data::Dumper::Quotekeys = 0;
    local $Data::Dumper::Useperl   = 1;
    local $Data::Dumper::Sortkeys  = 1;
    Data::Dumper::Dumper($arg);
    }

第二部分对 Text::Diff 做了类似的事情。它设置了各种参数,您可以根据口味进行调味。我这样做是为了向它传递两个字符串,我将它们变成数组引用中的行(因为这都在内存中):

sub my_diff {
    state $rc = require Text::Diff;
    my( $got,$expected,$context ) = @_;

    $context //= 3;  # lines around the diff to show

    my $diff = Text::Diff::diff
        [ split /^/m,dump_it( $got ) ],[ split /^/m,dump_it( $expected ) ],{ CONTEXT     => $context,STYLE       => 'Table',FILENAME_A  => 'got',FILENAME_B  => 'expected',OFFSET_A    => 1,OFFSET_B    => 1,INDEX_LABEL => "Ln",};
    chomp $diff;
    $diff .= "\n";

    $diff;
    }

所以现在你的程序的内容是这样的:

my $is_same = dump_it( $reference_ref ) eq dump_it( $extracted_ref );

pass();
if ($is_same){
    pass();
}else{
    fail();
    note( my_diff( $reference_ref,$extracted_ref,1 ) );
}