Perl でテストスクリプトを書くためのフレームワーク。Test::Harness に対応。Test::Simple パッケージに含まれている。Perl 5.6.2 以降から Perl にバンドルされるようになった。
Perl 5.004_05 以降に含まれている Test モジュールとは ok 関数の引数が異なるので、互換性がないので注意が必要である。
#!/usr/bin/perl use strict; use warnings; use Test::More tests => 1; BEGIN { use_ok('MyNewModule'); }
use_ok の中で use が実行されるので、別途同じモジュールを use する必要はない。
#!/usr/bin/perl use strict; use warnings; use Test::More tests => 1; ok('abc' =~ /b/);
#!/usr/bin/perl use strict; use warnings; use Test::More tests => 1; is(substr('abcdef', 0, 2), 'ab');
テスト対象が定義されているかどうかを確認してくれるので、自分で isa() を呼んでチェックするよりよい。
#!/usr/bin/perl use strict; use warnings; use Test::More tests => 2; use IO::File; my $fh = new IO::File; isa_ok($fh, 'IO::File'); isa_ok($fh, 'IO::Handle');
WiKicker のテストスクリプトの作成には Perl 5.005_03 でも標準バンドルされている Test モジュールを使用している。 テストのためだけに追加のモジュールを要求するのも悪いかなと思って。
しかし Perl 5.6.2 以降にはすでに標準バンドルされている Test::More にそろそろ移行したい。
5.005_03 で WiKicker を使っている人も少ないようだし WiKicker 0.25 からは Test::More を PREREQ_PM に追加することにしよう。 Test モジュールと Test::More モジュールは互換性がないので、順次テストスクリプトを修正していく予定。
テストファースト開発に慣れてしまうと、テストコード無しにプログラムを書くというのは不安でたまらなく感じてくる。
テストが欲しい。安らぎが欲しい。
今開発している WiKicker ベースの Web アプリケーションもだんだん機能が増えてきて、コードを触るのがコワくなってきた。
今回は Basic 認証等もあるので、WWW::Mechanize::CGI ではなくてきちんと deploy してから Test::WWW::Mechanize でテストすることにした。
Test::WWW::Mechanize、使ってみると WWW::Mechanize + Test::More よりテストを書くのも読むのも楽になった。
deploy が必要なリグレッションテストはさすがに t/ の下に入れておくのはどうかと思う。 プロジェクト的にはビルドサーバを用意して、そこで自動的にテストできるような環境を用意するのが良さそうだ。
Perl で Test::More を使ったテストを修正していて、fail するけど今すぐ直せないのがあったので TODO: { } で囲ったんだけれど何も変わらないじゃない。 あれそんな時は perldoc Test::More の TODO: BLOCK サブセクションでも TODO: { } で囲ってるじゃん。
「そもそもテストが TODO: な ブロック内だってことどうやって判定しているのよ、どんな Perl マジック?」と調べたら…… $TODO 変数設定されているか見ているだけだった(あるいは Test::More->builder->{Todo} が defined か)。 ドキュメント中の local $TODO = $why; の方が肝だった。 ああ、それは説明文するための optional な設定だと思ってたよ。
そもそも TODO: って文法的にはブロックの名前じゃなくてただのラベルか? ということで
TODO: { local $TODO = $why; ok( foo(), $test_name ); is( foo(42), 23, $test_name ); };
は
{ local $TODO = $why; ok( foo(), $test_name ); is( foo(42), 23, $test_name ); };
でいい訳で。完全に人向けの飾りだった。
「TODO:」? あんなの飾りです。偉い人にはそれがわからんのですよ。
良い子のみんなは $TODO 多用しちゃ駄目だぞ。
@tokuhirom 情報より。
Test::More::todo_skip を使う場合は中で last TODO; しているので TODO: が必要。 ちなみに Test::More::skip の中では last SKIP; しているので SKIP: が必要。
テストスクリプトで 「クラスメソッドの返り値のアサーションで、is に括弧をつけると動くけれど、とると動かなくなるのはなぜ?」とチームメンバに質問された。
#!/usr/bin/perl use warnings; use strict; use 5.10.0; package MyClass; sub color { 'blue' }; package main; use Test::More; is(MyClass->color, 'blue'); is MyClass->color, 'blue'; # wrong! done_testing;
簡略化すると上のような感じ。実行すると、
Useless use of a constant (blue) in void context at sample.t line 16. ok 1 Can't locate object method "is" via package "MyClass" at sample.t line 16. # Tests were run but no plan was declared and done_testing() was not seen.
となる。
これは間接オブジェクト構文(indirect object syntax)の罠にハマったケースだね。 間接オブジェクト構文は、例えば C++ の new っぽく
my $obj = new MyClass;
と書ける構文(MyClass::new が呼ばれる)。前述では MyClass::is 呼ぼうとして怒られていると。間接オブジェクト構文は perldoc perlobj で説明されている。
ちなみにis じゃなくて組み込み関数だと違う解釈になる。
say(uc MyClass->color);
とすると MyClass::uc が呼ばれるのではなくて uc(MyClass->color) と解釈されるので "BLUE\n" が出力される。
また以下みたいに、意図しないまま動いちゃう場合もあるので注意かな。
#!/usr/bin/perl use warnings; use strict; use 5.10.0; package MyClass; sub color { 'blue' }; sub is { 'MyClass2' } package MyClass2; sub color { 'red' }; package main; use Test::More; is MyClass->color, 'green'; done_testing;
これだと MyClass::is が呼ばれて 'MyClass2' が返ってきて、そして MyClass2 の color が呼ばれて 'red' が返ってくる(そして 'green' は使われないし、Test::More::is も実行されない)。
Useless use of a constant (green) in void context at sample.t line 21. 1..0 # No tests run!
困ったらカッコつけようぜ。
Naney (なにい) です。株式会社MIXIで SNS 事業の部長をしています。
※本サイトの内容は個人的見解であり所属組織とは関係ありません。