Hatena::Groupsubtech

NaN days

ブログを移転しています。最新の記事は motemen.hatenablog.com へどうぞ

2013-02-19

テストが失敗したときに再試行できるようにするモジュールを書きました

| 13:22 |  テストが失敗したときに再試行できるようにするモジュールを書きました - NaN days を含むブックマーク はてなブックマーク -  テストが失敗したときに再試行できるようにするモジュールを書きました - NaN days

Selenium を使ったときなどテストの状態が外部に依存しているような場合、状態が確実に変化するのを待つために sleep などしてみているけれどやりたいのはそういうことじゃないんだ! という訳で、テストが失敗したら少しウェイトを入れて再試行するモジュールを書きました。

GitHub - motemen/perl5-Test-Retry: Retry a code block for several times until a test function succeeds


無意味な例ですが、

use Test::More;
use Test::Retry max => 3, delay => 0.1; # exports retry_test(&)
my $x = 0;

retry_test {
    is $x++, 2, '$x++ == 2';
};

retry_test のブロック内でのテストが失敗しそうな場合、デフォルトでは 0.5 秒待機して最大 5 回リトライします。テストが成功する場合にはそのまま次のへ実行を移し、最大試行数を越えた場合は失敗します。

上の例だと、以下のような出力になります。

# test '$x++ == 2' failing; retry (2 remaining)
#          got: '0'
#     expected: '2'
# test '$x++ == 2' failing; retry (1 remaining)
#          got: '1'
#     expected: '2'

ok 1 - $x++ == 2

また、いちいちブロックで囲んでらんないという人のために、既存のテスト関数を書き換えるような機能も提供しています。

use Test::Retry override => [ 'is' ];

# または以下; prototype ごと変わるので BEGIN で
BEGIN { Test::Retry->override('is') }

is { func_with_some_random_lag(), $expected };

テスト関数に渡される引数を返すブロックを渡すと、以下と同じ動作をします。

retry_test {
    is func_with_some_random_lag(), $expected;
};

たとえば Selenium::Remote::Driver を使ったテストだと

$driver->find_element(...)->click;

retry_test {
    is $driver->get_title, ...;
};

みたいな感じにして、ページ読み込みを待つ手間が省けます。

どうぞご利用ください。