Blog

Perl Monger は Test::More の subtest が便利すぎるので頭にいれておくべきだと主張したい俺がいる件

Test::More の 0.94以後(2009-09-02)では subtest という機能が導入されており、これが非常に便利なのだが意外と利用されていないようなので、ちょっと宣伝させてもらいますね。

以下は Data::Recursive::Encode のテストケースなのだが、似たようなケースが頻出するわりに、抽象化するのが面倒だし、わけわからなくなること必至であり、かつまた、こんなものを複数のファイルにわけていてはメンテナンスが面倒なことは考えるまでもない。

チミチミと似たような数行のテストをかいたファイルを複数つくるぐらいならば、このように subtest の利用を考えるべきだとおもう。

ただし、これも他のツール同様、なんにでも適用すればいいというものではなく、使い方をまちがえれば、関係ないものがゴッチャリはいった .t ができあがるので注意するべきだろう。

use strict;
use warnings;
use Test::More;
use Data::Recursive::Encode;
use Encode;

# utility functions
sub U($) { decode_utf8($_[0]) }
sub u($) { encode_utf8($_[0]) }
sub E($) { decode('euc-jp', $_[0]) }
sub e($) { encode('euc-jp', $_[0]) }
sub eU($) { e(U($_[0])) }

# -------------------------------------------------------------------------

subtest "decode_utf8" => sub {
    my $D = sub { Data::Recursive::Encode->decode_utf8(@_) };

    is_deeply([$D->('あいう')], [U('あいう')], 'scalar');
    is_deeply([$D->(\('あいう'))], [\(U('あいう'))], 'scalarref');
    is_deeply($D->(['あいう']), [U('あいう')], 'arrayref');
    is_deeply($D->({'あいう' => 'えお'}), {U('あいう'), U 'えお'}, 'hashref');

    {   
        my $code = sub { };
        is_deeply(
            $D->(
                [   
                    'あいう', $code,
                    bless( ['おや'], 'Foo' )
                ]
            ),
            [ U('あいう'), $code, bless( ['おや'], 'Foo' ) ],
            'coderef,blessed'
        );
    }
    done_testing;
};

# -------------------------------------------------------------------------

subtest "encode_utf8" => sub {
    my $E = sub { Data::Recursive::Encode->encode_utf8(@_) };

    is_deeply([$E->(U 'あいう')], [('あいう')], 'scalar');
    is_deeply([$E->(\(U 'あいう'))], [\(('あいう'))], 'scalarref');
    is_deeply($E->([U 'あいう']), [('あいう')], 'arrayref');
    is_deeply($E->({U('あいう') , U('えお')}), {('あいう'),  'えお'}, 'hashref');

    {   
        my $code = sub { };
        is_deeply(
            $E->(
                [   
                    U('あいう'), $code,
                    bless( [U('おや')], 'Foo' )
                ]
            ),
            [ ('あいう'), $code, bless( [U('おや')], 'Foo' ) ],
            'coderef,blessed'
        );
    }
    done_testing;
};

# -------------------------------------------------------------------------

subtest "decode" => sub {
    my $D = sub { Data::Recursive::Encode->decode('euc-jp', @_) };

    is_deeply([$D->(eU('あいう'))], [U('あいう')], 'scalar');
    is_deeply([$D->(\(eU('あいう')))], [\(U('あいう'))], 'scalarref');
    is_deeply($D->([eU('あいう')]), [U('あいう')], 'arrayref');
    is_deeply($D->({eU('あいう') => eU('えお')}), {U('あいう'), U 'えお'}, 'hashref');

    {   
        my $code = sub { };
        is_deeply(
            $D->(
                [   
                    eU('あいう'), $code,
                    bless( [eU('おや')], 'Foo' )
                ]
            ),
            [ U('あいう'), $code, bless( [eU('おや')], 'Foo' ) ],
            'coderef,blessed'
        );
    }
    done_testing;
};

# -------------------------------------------------------------------------

subtest "encode" => sub {
    my $E = sub { Data::Recursive::Encode->encode('euc-jp', @_) };

    is_deeply([$E->(U 'あいう')], [eU('あいう')], 'scalar');
    is_deeply([$E->(\(U 'あいう'))], [\(eU('あいう'))], 'scalarref');
    is_deeply($E->([U 'あいう']), [eU('あいう')], 'arrayref');
    is_deeply($E->({U('あいう') , U('えお')}), {eU('あいう'),  eU('えお')}, 'hashref');

    {   
        my $code = sub { };
        is_deeply(
            $E->(
                [   
                    U('あいう'), $code,
                    bless( [U('おや')], 'Foo' )
                ]
            ),
            [ eU('あいう'), $code, bless( [U('おや')], 'Foo' ) ],
            'coderef,blessed'
        );
    }
    done_testing;
};

done_testing;