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

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

Test::Mock::Net::FTP というモジュールを書いた

表題の通りです。
というか、2009年ごろからチマチマと書いてたやつがある程度まともになったので、そろそろ CPAN にあげてもいいかなー、と思ってます。一応月曜に会社でコレ使ってるテストコード流して確認してから ship しようと思ってるので、リリースは月曜になる予定。月曜深夜ごろ、無事にshipしました。

基本的な使い方はこんな感じ。Synopsis 丸写しですが。

use strict;
use warnings;

use Test::More;
use Test::Mock::Net::FTP;

Test::Mock::Net::FTP::mock_prepare(
    'somehost.example.com' => {
        'user1'=> {
            password => 'secret',
            dir      => ['./ftpserver', '/ftproot'],
            override => { 
                ls => sub {
                    return qw(aaa bbb ccc);
                },
            },
        },
    }
);
my $ftp = Test::Mock::Net::FTP->new('somehost.example.com');
$ftp->login('user1', 'secret');
$ftp->cwd('datadir');
$ftp->get('file1');
my @files = $ftp->ls();# => ('aaa', 'bbb', 'ccc');
$ftp->quit();

この場合だと、ローカルファイルシステムの ./ftpserver を FTP サーバとみなして、Net::FTP で使うオペレーションをあれこれできます。(ls したり put とか get とか)。自分がよく知ってるメソッドはそれっぽく実装してあるし、よく知らないメソッドも空実装を一応入れてるので、それなりに動くはず。

この例では、ls に subref を渡してますが、こうすると ls をオーバーライドできます。

あと、intercept という機能を付けていて、

use Test::Mock::Net::FTP qw(intercept);
some_method_using_ftp();

みたいな感じにすると、some_method_using_ftp()で使ってる Net::FTP を丸ごと乗っ取ることもできます(Net::FTPインスタンスが Test::Mock::Net::FTP で置き換わる)。テストコード側で Net::FTP を渡せないような場合(多分レガシーコードですね)に有効だと思います。

背景とか

「21世紀に FTP とかねーよ」と思う方も多いかもしれませんが、ウチみたいな非Web 系だと、古い Solaris (2.6とか下手するともっと前とか)とか、VMS とか、その他見たこともないような謎の機械とかも普通に動いていて、そういう環境で頼りになる伝送手段は FTP ぐらいだったりします。

なので、伝送ツールとか普通に FTP を使って動いてるので、そういうのをテストできるといいなー、と思ったのですが、CPAN 見てもあんまりよさげなツールがないんだよね。

Net::FTP::MockとかTest::FTP::Serverくらいかな?どちらも、自分が欲しいなー、と思ってた頃にはまだ CPAN に上がってなかったと思う。ちなみに、Net::FTP::Mock はメソッドが全然たりてないので、たぶんちゃんと動かないと思う。Test::FTP は見た感じよさげだけど、使ったことない。

普通に Mock 系のモジュールを使うとか、Mock のラッパーを書いても良かったんだけど、練習も兼ねてがっつり作ってみました。

困ってること1

intercept は一応それなりに動くんだけど、@INC をどうこうするとかの正しいお作法が分からない。。。今はコンストラクタを乗っ取ってるだけなので、なんかダメなパターンがある気がします。

困ってること2

pasv_xfer とか Net::FTP::dataconn インスタンスを返すメソッドとか、どうやって使って、どう動くのかさっぱりわからないです。。。ぐぐってもあんまり使われてないみたいなので、まじめに実装する気がおきません。

困ってること3

どうすれば Windows で動かせるかは分かってはいるのですが、すげー大変そうなので、まだやってません。Unix 系でしか動きません。

何が大変かというと、File::Spec とか File::Basename がそのままでは使えないんです。FTP サーバ側は Unix 形式のパスにして、それ以外はプラットフォーム毎のパスで持たないといけない。まあこれができると、サーバのパス形式を Windows/Unix で切り替えたりとかできるようになるので、うれしいのだけど。。。

CPAN(2011/06/07 追記)

Test-Mock-Net-FTP