ぱいぱいにっき

Pythonが好きすぎるけれど、今からPerlを好きになりますにっき

Test::Deep + Data::Validator みたいなのほしいですね、はい

はい、続きまして、どうもマコピーです。

いきなりテスト期というか、そんな感じなので、いろいろ学んでいます。

で、僕はJSON APIなんぞを結構自由に作っているのですが、そのレスポンスをうまいことテストしたいな、と。

{
    entry => [
        { hoge_id => 1, card => { ... }, amount => 1, },
        { hoge_id => 1, items => [...] },
        { hoge_id => 1, point => 100 },
    ],
}

みたいな形式のレスポンスを返すとして(Perl形式ですけれど実際はJSONです。でもテストはPerlの時点でやってます)、モストフェイバリットテストモジュールなTest::Deepだとこれができないんですね。

use Test::Deep;
use Test::Deep::Matcher;

cmp_deeply $response, array_each({
    hoge_id => is_integer,
    card => is_hash_ref, # 無いときコケる
    items => ignore(), # これもダメ
    point => any(undef, is_integer) # ダメ
    amount => is_integer, # 当然ダメ
});

キー自体がないとコケるんですね。ハイ。
さてどうしましょうかねってなったときにどうすればいいすっかねって聞いたらData::Validaterにあるよって言われて、こんなかんじに書き換えました。

use Test::Deep;
use Data::Validater;

cmp_deeply $response, array_each(
    code(sub {
        my $got = shift;
        my $v = Data::Validater->new(
                hoge_id => { isa => 'Int' },
                card => { isa => 'HashRef', xor => [qw/items point/] },
                items => { isa => 'ArrayRef', xor => [qw/card point/] },
                point => { isa => 'Int', xor => [qw/card items/] },
                amount => { isa => 'Int', optional => 1 },
        );
        $v->with('NoThrow');
        $v->validate($got);
        return $v->has_errors;
    })
);

で、いけました。でもエラー出るとわけわかん感じになるし、これ以上入れ子にしたり出来ないんですよね。MouseX::Typesで型定義してけばいいけれどめんどうじゃないですか?????

なので両方のいいとこどり(Test::Deepの簡単に入れ子にしていけるのと、Data::Validaterのxorとoptional)出来るいい方法があればいいなって思いました。

こんなかんじです。