hero_picture

CGIプログラムをPlack::Testでテストする

以下のようなCGIプログラムのテストを書きたいとします。

fizzbuzz.cgi

1#!/usr/bin/perl
2use strict;
3use warnings;
4use CGI;
5my $q = CGI->new;
6my $number = $q->param('number');
7unless (defined $number) {
8print $q->header(
9-status => 200,
10-type => 'text/plain; charset=utf8',
11);
12print "Please set number";
13exit;
14}
15my $result = '';
16if ($number % 3 == 0) {
17$result .= 'Fizz';
18}
19if ($number % 5 == 0) {
20$result .= 'Buzz';
21}
22$result ||= $number;
23print $q->header(
24-status => 200,
25-type => 'text/plain; charset=utf8',
26);
27print $result;
28

ロジックが一緒に書かれているので、Test::Moreでテストしづらいですね。

こんなときはCGIプログラムをPSGIアプリに変換し、

Plack::Testでテストすると楽です。

PSGIアプリに変換するにはPlack::App::CGIBinを使って、

以下の内容のapp.psgiを作成します。

1#!/usr/bin/perl
2use strict;
3use warnings;
4use File::Basename;
5use Plack::Builder;
6use Plack::App::CGIBin;
7my $basedir = dirname(__FILE__);
8builder {
9mount '/' =>
10Plack::App::CGIBin->new( root => $basedir, exec_cb => sub { 1 } )->to_app;
11};
12

これでめでたくCGIプログラムはPSGIアプリになりました。

普通のPSGIアプリと同様に、plackupコマンドなどで実行できるようになります。

1$ plackup app.psgi
2

ブラウザなどで「http://localhost:5000/fizzbuzz.cgi?number=1」にアクセスすると実行できます。

PSGIアプリは、Plack::Testでテストすることができます。

先ほどのCGIプログラムのテストは、次のように書くことができます。

1use strict;
2use warnings;
3use Test::More;
4use Plack::Test;use HTTP::Request::Common;
5use Plack::Loader;
6use Plack::Util ();
7my $app = Plack::Util::load_psgi('app.psgi');
8test_psgi $app, sub {
9my $cb = shift;
10my $res;
11$res = $cb->(GET "/fizzbuzz.cgi?number=1");
12is $res->code, '200';
13is $res->content, '1';
14$res = $cb->(GET "/fizzbuzz.cgi?number=2");
15is $res->code, '200';
16is $res->content, '2';
17$res = $cb->(GET "/fizzbuzz.cgi?number=3");
18is $res->code, '200';
19is $res->content, 'Fizz';
20$res = $cb->(GET "/fizzbuzz.cgi?number=4");
21is $res->code, '200';
22is $res->content, '4';
23$res = $cb->(GET "/fizzbuzz.cgi?number=5");
24is $res->code, '200';
25is $res->content, 'Buzz';
26$res = $cb->(GET "/fizzbuzz.cgi?number=15");
27is $res->code, '200';
28is $res->content, 'FizzBuzz';
29};
30done_testing();
31

書きやすいですね。