2011-10-09 9 views
11

私はPHPUnitテストの複雑なセットを持っています。その中には、何らかの理由でタイムアウトが発生することがある、世界中のサーバーに接続するものがあります。PHPUnit - 自動的に失敗したテストをX回再試行しますか?

サーバがタイムアウトしたときにテストに失敗するのではなく、単にそのテストを1回以上再試行してから、実際に失敗とマークします。

今、私の状況を把握するための最良の方法ではないことを理解しています。 1つのより良い解決策は、サーバーを修正することです。しかし、これは今私のコントロール外です。

PHPUnitに失敗したテストケースをX回再テストするように指示し、毎回失敗した場合にのみ失敗とマークする方法です。

アイデア?

編集:多くの方が、私がでなく、であるという有用な提案で回答しました。ご理解いただきありがとうございます。しかし、具体的には、フルシステム(リモートサーバーを含む)の動作をテストするテストスイートを作成することです。私はコードの特定の部分を外部からの模擬応答でテストするという概念を理解していますが、私のテストの一部が "完全なスタック"をテストするならば、夜間もよく眠ります。

+2

「あなたのホストではない」と言うときは、「あなたのシステムの一部ではない」と言います。したがって、テストに含めるべきではありません。とにかく影響を与えることができず、結果を改ざんするからです。あなたはテスト '$ this-> assertEquals(1、rand(0,1))'を決して作成しませんでしたか?これは、不確実な外部システムが含まれている場合に起こります。 – KingCrunch

答えて

10

PHPUnitはこの動作をそのまま使用することはできませんので、ループを自分でコーディングする必要があります。それを必要とするすべてのテストでそれを実行する代わりに、PHPUnit_Framework_TestCaseを拡張し、その機能を提供するカスタムテストケースベースクラス(まだ持っていない場合)を作成します。

あなたは空想取得しparent::testBare()を呼び出し、注釈など@retry 5、ループ回数の数をチェックするためにtestBare()をオーバーライドして、最後を除くすべての例外(またはサブセット)を飲み込むことができます。

public function runBare() { 
    // I'll leave this part to you. PHPUnit supplies methods for parsing annotations. 
    $retryCount = $this->getNumberOfRetries(); 
    for ($i = 0; $i < $retryCount; $i++) { 
     try { 
      parent::runBare(); 
      return; 
     } 
     catch (Exception $e) { 
      // last one thrown below 
     } 
    } 
    if ($e) { 
     throw $e; 
    } 
} 

それとも、再試行回数をパラメータとして呼び出し可能な閉鎖を/取る同様のヘルパーメソッドを作成し、それを必要とする各テストからそれを呼び出すことができます。

public function retryTest($count, $test) { 
    // just like above without checking the annotation 
    ... 
     $test(); 
    ... 
} 

public function testLogin() { 
    $this->retryTest(5, function() { 
     $service = new LoginService(); 
     ... 
    }); 
} 
+0

こんにちはDavidさん、何をすべきか詳細を教えてください。失敗した場合は、一度テストケースを再試行しなければなりません。 – Deep123

+0

@ Deep123どの部分が明確ではありませんか? –

+0

返事ありがとうDavid。注釈を使用せずに失敗した場合は、テストケースを再試行します。私がやったこと。 $ retryCount = 2を使って私の基本クラスに[あなたの答えに定義されているように]実行時ベア関数のコードを入れました。この時点後、私は明確ではありません:( – Deep123

7

あなたの質問に対する答えは正確ではありませんが、私はとにかくそれを言います:テストはリモートリソースを含んではいけません(特にローカルミラーとは異なり手が完全に外れている場合)。接続を別のクラス(たとえばConnection)にカプセル化し、テスト内でこれらのオブジェクトをモックし、リモートホストが返す静的応答で作業する必要があります。

+1

これは単体テストでも当てはまりますが、自動受入れテストでは、外部サービスを模擬するかどうかについてはまだまだ多くの議論があります。私たちは選択しなかったので、テストの脆さを増やすことができます。そのような場合は、再試行が役立ちます。 –

1

私はそれがサポートされているとは思わないが、誰かが間違っていると分かるかもしれないが、その場合は驚くだろう。

あなたができることは、取得するテストメソッドですぐにアサートするのではなく、ループの外側で結果がアサートされるX回のループと成功時のブレークです。

この簡単な方法は、既に考えていたことですが、各テストメソッドにコードを追加するという欠点があります。あなたはそれらの多くを持っている場合、それはメンテナンスの負担に追加されます。

さらに自動化する場合は、PHPUnit_Framework_TestListenerを実装し、失敗したテストの数を連想配列に保ち、テスト実行と比較することができます。このルートはどれくらい実現可能かはわかりませんが、試してみてください。

0

あなたはDB接続アサーションを作成し、他のテストでそのテストをあなたのDB接続として実装できるはずです。そのテストの中で、必要な回数だけ試してみることができ、Xが試した後にfalseを返すことができます。

3

ライブサーバーに接続するのではなく、モックオブジェクトやフィクスチャを使用して、他の場所からの応答がテストに影響しないようにしてください。

依存関係インジェクションを使用して、あなたが指示したデータと応答コード(コードの記述方法によって異なる)を返す特定のHTTPクライアントを使用できます。理想的には、ユニットテストは外部の影響から独立している必要があります。あなたはあなたがテストしているものを管理し、例えば404または500のエラーを強制することはテストの別の部分でなければなりません。

非決定論的なテストをハックしようとするよりも、コードを変更して模擬テストとフィクスチャをテストできるかどうかを調べる方が良いでしょう。

もちろん、あなたがすでに知っているかもしれないこととは別に、PHPUnitにテストが失敗するよう指示する方法はわかりません。それはツールがやっているべきことに完全に反しているようです。

+0

+1、重要な最後の文章:「ツールがやるべきこととは全く反対のようです」 – hakre

関連する問題