prove (Test::Harness) コマンドの --state オプション
テストが膨大になっていくと,あるテストでは時間がかかったりして「そのテストはもう成功することがわかっとるっちゅうねん;失敗するテストだけ再テストしたいっちゅうねん」ってことになったりします。そんなときに使えるのが prove
コマンドの --state
オプションです。
--state
オプションに failed
という引数をわたすと,「テストの対象は前回 fail したテストスクリプトのみ対象」という意味になります。ステートを保存する save
と併用して指定してみます。
% prove --state failed,save No saved state, selection will be empty Files=0, Tests=0, 0 wallclock secs ( 0.00 usr + 0.00 sys = 0.00 CPU) Result: NOTESTS
「No saved state」と怒られてしまいました。なので初回のみステートを明示的に保存する必要があります。
% prove --state save t/10_parse_args.....ok t/11_util_search....ok t/12_util_text......ok t/20_ctrl_words.....1/? # Failed test at t/20_ctrl_words.t line 26. # Looks like you failed 1 test of 5. t/20_ctrl_words..... Dubious, test returned 1 (wstat 256, 0x100) Failed 1/5 subtests Test Summary Report ------------------- t/20_ctrl_words (Wstat: 256 Tests: 5 Failed: 1) Failed test: 5 Non-zero exit status: 1 Files=4, Tests=48, 2 wallclock secs ......
4つのテストのうち1つだけ失敗しました。
これでステートが保存されたので,もっかい --state failed,save
を指定して実行してみます。
% prove --state failed,save t/20_ctrl_words....1/? # Failed test at t/20_ctrl_words.t line 26. # Looks like you failed 1 test of 5. t/20_ctrl_words.... Dubious, test returned 1 (wstat 256, 0x100) Failed 1/5 subtests Test Summary Report ------------------- t/20_ctrl_words (Wstat: 256 Tests: 5 Failed: 1) Failed test: 5 Non-zero exit status: 1 Files=1, Tests=5, 0 wallclock secs ...... Result: FAIL
さきほど失敗した t/20_ctrl_words
というテストケースだけ実行されました。あとはこのテストケースが通るようモジュールを修正していくだけです。
Test::Harness 3.14 から,テストスクリプトの修正日時をみて,前回実行時以降に修正したものを対象にする「fresh
」という引数が追加されました。
% touch t/12_util_text.t % prove --state fresh,failed,save t/12_util_text.....ok t/20_ctrl_words....1/? # Failed test at t/20_ctrl_words.t line 26. ...... snip snip snip ...... Files=2, Tests=8, 1 wallclock secs ...... Result: FAIL
fresh,failed
のように指定したので,更新されたテストスクリプトが先に実行され,次に前回 fail したスクリプトが実行されました。--state failed,fresh,save
のような順序にすると,先に fail したスクリプトが実行されます。
--state
に指定できるトークンには,いままでに指定したような「テスト対象を絞り込む」タイプのものと,new
, old
のように「テストを実行する順序を制御する」タイプのものがあります。このへんは prove コマンドのマニュアル や App::Prove::State の perldoc を読めばわかりますし,App::Prove::State のソース(具体的には sub apply_switch
)を読めば((最初,複数オプションを指定すると AND 条件になってしまうのではないかと sub App::Prove::State::apply_switch
をオーバーライドするツールとか書いてました。実際には後述のように OR 条件になってます。ま,そんな失敗談はさておき,ちょっと凝った条件でテスト対象を絞り込みたい場合は,apply_switch
あたりを自分で書くといいかもしれません。))具体的に動作がわかります。
で,たとえば --state failed,all,save
のようにすると,全テストスクリプトを対象とするんだけど fail したテストを最初に実行してね,という意味になります(ちとわかりにくいんですが,先頭のトークンの絞り込み結果から順番にテスト対象にマージされていくってことです)。
さきほどから「ステートを保存」と書いてきましたが,prove
を実行したディレクトリに .prove
という単一 YAML ファイルで保存されます。実行成否だけではなく,テストの実行にかかった時間なども記録されているので,このファイルを使えばテストケースの実行時間が遅いものを調べることもできます。ということを id:dann さんが Perlで遅いテストケースを調査する方法 - dann's blog - # で書いてました。
とるにたらない注意点ですが,fresh
オプションは,あくまで「テストスクリプトの mtime」をみているだけです。なので過信して --state failed,fresh,save
で,がしがしとモジュールを修正していって,通った通ったと喜んでいると,すでに pass したテストが動かなくなっていた!ということもあります(あたりまえ)。デバッグが一通りすんだら --state hot,all,save
するなり --state
つけずに動かすなり,.state
ファイルを削除するなりするべきでしょう((自分ローカルで開発しているなら,Makefile の test ターゲットには --state fresh,failed,save
したものを,fulltest ターゲットに --state hot,all,save
を指定するというのもいいかもしれません。))。