連想配列を使った悪い例

前回の続き。
ハッシュのランダム化」に関係なくダメなコードの例。

※以降の実行結果は、すべてPerl v5.18.1によるものです。

こういうのダメ、絶対。

use strict;
use warnings;
use v5.10;

use Test::More;

my %h = ( a => 'foo', b => 'bar' );

my $exp = join ',' , %h;
is join(',', %h), $exp, 'compare hash.';

for (1..5) {
    my %tmp = %h;
    is join(',', %tmp), $exp, 'compare hash.';
}

done_testing;

これを10回くらい実行すると、1回くらいこうなる。
$ perl aaa.pl
ok 1 - compare hash.
ok 2 - compare hash.
ok 3 - compare hash.
ok 4 - compare hash.
ok 5 - compare hash.
ok 6 - compare hash.
1..6

けど、十中八九こうなる。
$ perl aaa.pl
ok 1 - compare hash.
not ok 2 - compare hash.
# Failed test 'compare hash.'
# at aaa.pl line 14.
# got: 'a,foo,b,bar'
# expected: 'b,bar,a,foo'
not ok 3 - compare hash.
# Failed test 'compare hash.'
# at aaa.pl line 14.
# got: 'a,foo,b,bar'
# expected: 'b,bar,a,foo'
ok 4 - compare hash.
not ok 5 - compare hash.
# Failed test 'compare hash.'
# at aaa.pl line 14.
# got: 'a,foo,b,bar'
# expected: 'b,bar,a,foo'
ok 6 - compare hash.
1..6

同じ連想配列をjoinでつなげる分には一致するが、
代入の度に順番が変わるので、うまくいかない。

というか、こういう比較方法は悪い例で、
せめて、keysを使って各要素を比較すべき。

たとえば、こんな感じに。

use strict;
use warnings;
use v5.10;

use Test::More;

my %exp = ( a => 'foo', b => 'bar' );

for ( 1..5 ) {
    my %got = %exp;
    foreach ( keys %exp ) {
        is $got{$_}, $exp{$_}, 'compare hash.';
    }
}

わざと、何回も代入と比較してるけど、1回で十分。
あと、Test::Moreにはこういう関数もある。

use strict;
use warnings;
use v5.10;

use Test::More;

my %exp = ( a => 'foo', b => 'bar' );

my %got = %exp;
is_deeply \%got, \%exp, 'compare hash.';

my %wrong = ( a => 'foo', b => 'hoge' );
is_deeply \%wrong, \%exp, 'compare hash.';

done_testing;

実行結果はこんな感じ。
$ perl ccc.pl
ok 1 - compare hash.
not ok 2 - compare hash.
# Failed test 'compare hash.'
# at ccc.pl line 13.
# Structures begin differing at:
# $got->{b} = 'hoge'
# $expected->{b} = 'bar'
1..2
# Looks like you failed 1 test of 2.

おしまい。

Leave a Comment