tsucchi’s diary(元はてなダイアリー)

はてなダイアリー(d.hatena.ne.jp/tsucchi1022)から移行したものです

Test::Module::Used の話

YAPC::Asia も近いので、久々に Perl の話を書こうと思います。僕が作った Test::Module::Used の話。とはいえ、新しい話は特に無いので、今までのまとめをしようと思います。

これは何?

CPAN モジュールを書く際、Makefile.pm に、依存するモジュールを requires, テストで使うモジュールを test_requires に書きますが、往々にして書き忘れることがあります。また、逆に use していないのに、requires/test_requires に指定してしまうことがあります。

このモジュールはそういった「依存指定漏れ」や「過剰な依存指定」を見つけるのに使います。

前にも書きましたが、Test::Dependenciesというモジュールが大体同じ機能を持っているらしいです。(つーかこのモジュールを参考に改良を加えたものです)

使い方

CPAN レイアウトにして、テストコードを置くディレクトリに配置します。僕は module_used.t というテスト名にしています。author_tests 用のディレクトリ(xt)に置くのがいいと思います。(これ自身は依存するモジュールが結構多いため)

典型的な使い方は、

#!/usr/bin/perl -w
use strict;
use warnings;
use Test::Module::Used;
my $used = Test::Module::Used->new();
$used->ok;

こんな感じ。これでほとんどのケースは対応できるはずです。

チェック対象からはずしたいモジュールがある場合、

use strict;
use warnings;
use Test::Module::Used;
my $used = Test::Module::Used->new();
$used->push_exclude_in_libdir( qw(Some::Module) );
$used->push_exclude_in_testdir( qw(Test::SomeModule) );
$used->ok;

のようにします。Makefile.PL(META.yml)で Some::Module, Test::SomeModule を書かずに、lib ディレクトリ内で、Some::Moduleが使われていてもテストが成功し、test のディレクトリ(t)で、Test::SomeModule が使われていてもテストが成功します。(意図的に指定漏れさせることができます)

Makefile.PL(META.yml)側の依存指定を無視したい場合、コンストラクタで指定します。

use strict;
use warnings;
use Test::Module::Used;
my $used = Test::Module::Used->new(
    exclude_in_build_requires => [qw(Module::AA)],
    exclude_in_requires       => [qw(Module::BB)], 
);
$used->ok;

とすると、Makefile.PL(META.yml) のbuild_requires に Module::AA が指定されていて、実際に使われていなくても、そして requires に Module::BBが指定されていて、実際に使われていなくてもテストが成功します。(意図的に過剰に指定させることができます)。

基本的な動作

MATA.yml から requires, build_requires を引っこ抜いて、依存指定されたモジュールをリスト化します。モジュール側からは、lib, t をスキャンして、lib 配下の .pm と t 配下の .t と .pm を抜き出して、そこで use されているモジュールを抜き出します。このとき、コアモジュールと、lib/t 内で package 宣言されたモジュールは除きます。で、META.yml のリストと、スキャンしたモジュールのリストをつき合わせて、差異がないかをテストしています。

うまく扱えないモジュール

ほとんどのモジュールはデフォルトでテストできると思いますが、駄目なパターンがいくつか分かっています。

サブモジュールを持っているものを use している場合

Test::Module::Used でやりたいのだけど、できないことでも書いたのですが、DBIx::Skinny みたいに、サブモジュールを持っているモジュールを use している場合は使っているサブモジュールを全部 Makefile.PL(META.yml)で指定してあげないとうまく動きません。(もしくは、exclude 系を調整する必要があります)

Test::Module::Used 側で、CPAN(やその他のモジュール情報を提供してくれるサービス)に問い合わせることで、対応出来なくは無いのですが、環境依存でテストが通ったり通らなくなったりするのは嫌だし、サブモジュールが独立することもあったりすると思うので、当面このままにしておこうと思っています。

あれば使う系

タイトルがイマイチですが、JSON に対する、JSON::XS みたいなやつです。動的に require してるやつは、うまく動きません。この場合は、Makefile.PL(META.yml)で依存モジュールに指定するのは嫌なはずなので、exclude 系のパラメータを調整する必要があります

Catalyst::Plugin

だけではないのかもしれませんが、use しなくても use 相当のことが出来てしまうモジュールはうまく動きません。Catalyst::Plugin に関しては、時間があれば対応してみようかな、と思います。

今後について

大体作りたいものは出来ているのですが、時間があれば Catalyst::Plugin 対応とかやってみようかな、と思っています。あと、テスト対象を絞れる(「依存漏れだけチェック」、とか「lib は見るけど t は見ない」とか)できると嬉しいのかな、と思います。