【问题标题】:Testing that two hash keys have equal structures in Perl在 Perl 中测试两个哈希键是否具有相同的结构
【发布时间】:2021-11-23 18:41:33
【问题描述】:

我正在编写一个单元测试,我必须检查两个散列变量(散列的散列)的关键结构是否相同。键值可以不同。哈希的深度是任意的。

Test::Deep 看起来很理想,但我不知道如何让cmp_deeply 忽略这些值。

use Test::Deep;

my %hash1 = ( key1 => "foo", key2 => {key21 => "bar", key22 => "yeah"});
my %hash2 = ( key1 => "foo", key2 => {key21 => "bar", key22 => "wow"});

cmp_deeply(\%hash1, \%hash2, "This test should not fail");

输出:

not ok 1 - This test should not fail
#   Failed test 'This test should not fail'
#   at demo.pl line 13.
# Compared $data->{"key2"}{"key22"}
#    got : 'yeah'
# expect : 'wow'

如果哈希具有已知结构,我可以使用值为ignore() 的测试变量。但是,就我而言,最好的解决方案是我不必更新测试代码中的结构。

我尝试使用Data::Walk 遍历%hash1 并检查%hash2 中是否存在每个键,但发现很难从$Data::Walk::container 值中获取当前键。

对于合适的比较工具有什么想法吗?

【问题讨论】:

    标签: perl testing data-structures hash


    【解决方案1】:

    您似乎需要忽略这些结构中的叶子,否则会进行比较。

    然后可以比较两个结构之间到叶子的所有路径,忽略叶子。

    Data::Leaf::Walker 模块可以帮助生成所有叶子的路径数组。然后需要比较这些,Test::Deep 及其包比较只是工具。

    use warnings;
    use strict;
    use feature 'say';
    
    use Data::Leaf::Walker;
    use Test::More qw(no_plan);
    use Test::Deep;
    
    my %h1 = (key1 => "foo", key2 => {key21 => "bar", key22 => "yeah"});
    my %h2 = (key1 => "foo", key2 => {key21 => "bar", key22 => "wow"});
    
    my @key_paths_h1 = Data::Leaf::Walker->new(\%h1)->keys;
    
    my @key_paths_h2 = Data::Leaf::Walker->new(\%h2)->keys;
    
    # Now compare @key_paths_h1 and @key_paths_h2
    # Order of arrayrefs in the top-level arrays doesn't matter
    # but order of elements in each arrayref does 
    cmp_bag(\@key_paths_h1, \@key_paths_h2, 'key-paths');
    

    这会按预期打印,ok 1 - key-paths。更改任何键都以not ok 1 ... 结束


    说到这里,我想提一下这个模块提供了一个迭代器

    my $walker = Data::Leaf::Walker->new($data_structure_ref);
    
    while ( my ($keys_path, $value) = $walker->each ) {
        say "[ @$keys_path ] => $value"
    }   
    

    这样我们可以同时获得路径和它们的值,一次弹出一个。只有几个,但选择得当,方法。请参阅文档。

    【讨论】:

      【解决方案2】:

      这是一个手动操作的示例:

      use strict;
      use warnings;
      use experimental qw(signatures);
      use Test::More;
      
      {
          my %hash1 = ( key1 => "foo", key2 => {key21 => "bar", key22 => "yeah"});
          my %hash2 = ( key1 => "foo", key2 => {key21 => "bar", key22 => "wow"});
          ok(cmp_keys(\%hash1, \%hash2), "Hash keys identical");
      }
      done_testing();
      
      sub cmp_keys( $hash1, $hash2 ) {
          my @keys1 = flatten_keys( $hash1 );
          my @keys2 = flatten_keys( $hash2 );
          return 0 if @keys1 != @keys2;
          for my $i (0..$#keys1) {
              return 0 if $keys1[$i] ne $keys2[$i];
          }
          return 1;
      }
      
      sub flatten_keys( $hash ) {
          my @keys;
          my $prefix = '';
          _flatten_keys( $hash, $prefix, \@keys);
          return sort @keys;
      }
      
      sub _flatten_keys ( $hash, $prefix, $keys) {
          # $; The subscript separator for multidimensional array emulation,
          #    default value is "\034" = 0x1C
          my $sep = $;;
          for my $key (keys %$hash) {
              if (ref $hash->{$key} eq "HASH") {
                  _flatten_keys( $hash->{$key}, $prefix . $key . $sep, $keys );
              }
              push @$keys, $prefix . $key;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-10
        • 2019-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-19
        • 2014-11-26
        • 2016-03-11
        相关资源
        最近更新 更多