CGIの単体テストは面倒です。Perlお決まりの Test::More と prove でテストしたいし、Webサーバを立ち上げるのかという問題もある。
どうやらこういう場合の定番は HTTP::Request::AsCGI のようなので、試してみた。
こんな感じ。
use strict; use Test::More; use HTTP::Request::Common; use HTTP::Request::AsCGI; use CGI; BEGIN { # Create new HTTP::Request::AsCGI instance and setup my $c = HTTP::Request::AsCGI->new( GET 'http://example.com/path?key1=val1&key2=val2-1&key2=val2-2' )->setup; # Test environment variables is($ENV{REQUEST_METHOD}, 'GET', '$REQUEST_METHOD'); is($ENV{HTTPS}, 'OFF', '$HTTPS'); is($ENV{HTTP_HOST}, 'example.com:80', '$HTTP_HOST'); is($ENV{SERVER_NAME}, 'example.com', '$SERVER_NAME'); is($ENV{SERVER_PORT}, 80, '$SERVER_PORT'); is($ENV{REQUEST_URI}, '/path?key1=val1&key2=val2-1&key2=val2-2', '$REQUEST_URI'); is($ENV{QUERY_STRING}, 'key1=val1&key2=val2-1&key2=val2-2', '$QUERY_STRING'); is($ENV{PATH_INFO}, '/path', '$PATH_INFO'); is($ENV{SCRIPT_NAME}, '/', '$SCRIPT_NAME'); # Test CGI::param my $q = new CGI; my @param = $q->param; my @value = $q->param('key2'); ok(eq_array(\@param, ['key1', 'key2']), '$q->param'); is($q->param('key1'), 'val1', '$q->param(\'key1\')'); ok(eq_array(\@value, ['val2-1', 'val2-2']), '$q->param(\'key2\')'); # Test Response code, header and content $q->charset('utf-8'); print $q->header('text/plain'); print 'Hello, world.'; my $r = $c->restore->response; is($r->code, 200, 'Status:'); is($r->header('Content-Type'), 'text/plain; charset=utf-8', 'Content-Type:'); is($r->content, 'Hello, world.', 'CONTENT'); } done_testing;
HTTP::Request::AsCGI のコンストラクタの入力パラメータは HTTP::Request オブジェクトです。HTTP::Request::Common を使えば簡単にセットアップできる。
で、生成した HTTP::Request::AsCGI のインスタンスに対して setup を呼出せば、試験準備完了。上のコードにあるように、環境変数もちゃんとセットされるし、CGI.pm のメソッドも動きます。
出力のテストをする場合は、$c->restore->response で HTTP::Response オブジェクトに復元して各種メソッドでチェックすればよろしい。
ただし、上のコードにあるようにちょっとクセがあって、
- http: のリクエストのとき、$ENV{HTTPS} にはなぜか 'OFF' が設定される(普通は undef)
- ポート番号を指定しないリクエストでも $ENV{HTTP_HOST} に ':80' がつく(普通ブラウザはポートを指定しない)
- $ENV{SCRIPT_NAME} は '/' 固定。なので $ENV{PATH_INFO} もそれにしたがう
となりますので、場合によってはアプリ側に細工が必要になると思います。