テストの重要性は、改めて説明しなくてもわかると思うので割愛します。 ここではAPIエンドポイントに対するテストを書く方法を示します。
例によって雛形作成時にテストファイルが作られているので下記のファイルをまとめて削除します。
- t/00_compile.t
- t/01_root.t
- t/02_mech.t
- t/03_assets.t
- t/06_jshint.t
テストで接続するデータベースの名前をnopaste
からnopaste_test
に変更します。
"dbi:mysql:database=nopaste_test;host=localhost;", 'root', '', {
設定ファイルは、初めて$c->config
を呼んだ時(この場合のデフォルトをdevelopment)もしくは、script/nopaste-server
の内部でオプションが提供された場合に読み込まれます。
テストの場合は、t::Util
内で環境変数のPLACK_ENV
にtest
という文字列を入れており、これによってテスト用の設定ファイルが読み込まれるようになります。
詳しく知りたい場合は、Amon2::load_config
あたりを読んでみてください。
テスト時はTest::mysqld
を使用してMySQLを新たに立ち上げ、まっさらな状態で始めるのが良いのですが、Mac環境ではTest::mysqld
を動作させるのが面倒なため別途データベースを作成します。
そして、t::Util
をインポートするタイミングでデータベースを削除して再度作り直します。
DROP DATABASE IF EXISTS nopaste_test;
CREATE DATABASE nopaste_test;
USE nopaste_test;
DROP TABLE IF EXISTS text;
本来なら、Memcachedについてもテスト時の動作をケアすべきですが、今回テストする範囲ではMemcachedは呼び出されないため割愛しました。
気になる場合はTest::Memcached
のドキュメントを参照してください。
ファイルの一番下に、もともとSQLiteを初期化するコードが書かれています。 SQLiteの分を削除し、MySQLを初期化するように変更します。
最後のNoPaste->bootstrap
は、Webアプリとして読み込まれていない場合(テスト内のリクエスト処理部以外)でもNoPaste
のコンテキストを作成し、DB等にアクセスするために必要な処理です。
use NoPaste;
{
system("mysql -uroot < sql/cleanup_for_test.sql");
system("mysql -uroot nopaste_test < sql/mysql.sql");
NoPaste->bootstrap;
}
これでテストを記述する準備が整いました。
use strict;
use warnings;
use utf8;
use t::Util;
use Test::More;
use Test::More::UTF8;
use Test::Pretty;
use Test::Deep;
use Test::Deep::JSON;
use Plack::Test;
use Plack::Util;
use HTTP::Request::Common;
use NoPaste::Repository::Text;
my $test = Plack::Test->create(Plack::Util::load_psgi 'script/nopaste-server');
subtest 'GET /api/text/:id' => sub {
subtest 'データがない場合' => sub {
my $res = $test->request(GET '/api/text/1');
is $res->code, 404 or diag $res->content;
cmp_deeply $res->content, json({
status_code => 404,
message => 'Not Found.',
});
};
subtest 'データがある場合' => sub {
NoPaste::Repository::Text->create('test');
my $res = $test->request(GET '/api/text/1');
is $res->code, 200 or diag $res->content;
cmp_deeply $res->content, json({
id => 1,
text => 'test',
});
};
};
テストファイルを単独で実行する場合はperl
で実行します(prove
でも実行できます)。
$ carton exec perl t/api/text.t
特定のディレクトリ以下のテストを全て実行するにはprove
を使用します。
ディレクトリを省略した場合、t
ディレクトリをテストします。
prove
の動作や設定についてはドキュメントを参照してください。
$ carton exec prove
POST /api/text
とPUT /api/text/:id
についても同様のテストを記述してください。
丁寧に条件を書くとすると、これくらいになるはずです。
subtest 'POST /api/text/:id' => sub {
subtest 'textパラメータがない場合' => sub {};
subtest 'textパラメータがある場合' => sub {};
};
subtest 'PUT /api/text/:id' => sub {
subtest 'データがない場合' => sub {};
subtest 'textパラメータがない場合' => sub {};
subtest 'データがある場合' => sub {};
};
多くのテスト用モジュール、関数が登場しているので、これらのモジュールのドキュメントを読むと理解が進みます。
- Test::More
subtest
is
diag
done_testing
- Test::Deep
cmp_deeply
- Test::Deep::JSON
json
- Plack::Test