以下は、aとbに渡された数字を足し算するだけの簡単な(?)CGIです。
#!/usr/bin/env runghc {- sum.cgi -} import Network.CGI import Control.Monad cgiOutput (Just n) = do setHeader "Content-Type" "text/plain" output $ show n ++ "\n" cgiOutput Nothing = do setHeader "Content-Type" "text/plain" output "" cgiMain = do a <- getInput "a" b <- getInput "b" cgiOutput $ foldl (liftM2 (+)) (Just 0) (map (liftM read) [a, b]) main = runCGI $ handleErrors cgiMain
CGIを動かす
このCGIを動作させるためだけにApacheを用意するのはちと面倒です。perlからこのCGIを動かしたい場合には*1、マニュアルにあるように以下のようにします*2。
plackup -MPlack::App::CGIBin -e 'Plack::App::CGIBin->new(root => "/path/to/cgi-bin")->to_app'
サーバが立ち上がったら、 http://localhost:5000/sum.cgi などにアクセスすればOKです。なおPlack::App::CGIBinはシェバンで動作が変わり、perlだとevalでそれ以外だとforkしてexecされます。
テストを書く
PerlにはCGI::Testというモジュールがあり、これを用いれば以下のようにテストを書くことができます。
use CGI::Test; my $ct = CGI::Test->make( -base_url => "http://a", -cgi_dir => "t/cgi-bin", ); my $page = $ct->GET("http://a/sum.cgi?a=1&b=3"); print "1..1\n"; ok 1, $page->raw_content eq "4\n";
ただ、 CGI::Test は最終リリースが2001年であり、Test::Moreとok関数の名前が被ってたり "defined(%hash) is deprecated" なwarningが出たり-base_urlが必須だったりと実用的に難しい状態です。
そこで、Plack::Testを使うとこのテストは以下のように書けます。
use Test::More; use Plack::Test; use HTTP::Request::Common; use Plack::App::CGIBin; test_psgi( app => Plack::App::CGIBin->new(root => "t/cgi-bin")->to_app, client => sub { my $cb = shift; my $res = $cb->(POST "/sum.cgi", [a => 1, b => 4]); is $res->content, "5\n"; }, ); done_testing;
さらにTest::WWW::Mechanize::PSGIを使うと、ページ遷移を含めたテストも簡単に書けます*3。
use Test::More; use Test::WWW::Mechanize::PSGI; use Plack::App::CGIBin; my $mech = Test::WWW::Mechanize::PSGI->new( app => Plack::App::CGIBin->new(root => "t/cgi-bin")->to_app, ); $mech->post_ok('/sum.cgi', {a => 7, b => 2}); $mech->content_is("9\n"); done_testing;
2010-11-17 追記
突っ込みもらったので、追記しときます。
CGI ってのは STDIN/STDOUT/Environment variables により IPC する excecutable なんだからさ、その特性をいかして、ちゃんと普通にテストできるでしょ
my $output = run_cgi(cgi => 'path/to/cgi', env => {...}, input => ...); とかで十分テストできる気がする。
まあ確かに、テストするためだけにわざわざPSGIを経由するってのは複雑になるだけで本質的ではないですね。たまたま今ある道具を組み合わせたら苦労せずにテストが書けちゃったってだけの話で。
2011-05-12 追記
LWP::Protocol::PSGIを使えば、WWW::MechanizeをそのままPSGIアプリケーションのテストに使えますね!