2013-04-12 4 views
5

私はPythonで小さなジョブスケジューラを作成しています。スケジューラーには一連の呼び出し可能関数と依存関係を与えることができ、呼び出し可能関数を実行して、その先行関数の前にタスクが実行されていないことを確認する必要があります。Python unittestを使用して非確定的な結果を返す関数のテスト

私はテスト駆動型のアプローチに従おうとしており、依存性の処理をテストする問題にぶつかってきました。私のテストコードは次のようになります。

def test_add_dependency(self): 
    """Tasks can be added with dependencies""" 
    # TODO: Unreliable test, may work sometimes because by default, task 
    #  running order is indeterminate. 
    self.done = [] 
    def test(id): 
     self.done.append("Test " + id) 
    s = Schedule() 
    tA = Task("Test A", partial(test, "A")) 
    tB = Task("Test B", partial(test, "B")) 
    s.add_task(tA) 
    s.add_task(tB) 
    s.add_dependency(tA, tB) 
    s.run() 
    self.assertEqual(self.done, ["Test B", "Test A"]) 

問題は(ときどき)この試験は、私は、依存関係の処理コードを追加しても、前に働いていたということです。これは、特定の順序でタスクを実行する必要があるとは指定されていないためです。したがって、依存関係情報が無視されても、正しい順序は完全に有効な選択です。

このような「偶発的な」成功を避けるためのテストを書く方法はありますか?これは、テスト駆動型の "テストを失敗させずにコードを書いてはいけません"というアプローチをとる場合、これはかなり一般的な状況です。

+0

私は意図的に多くの可能な選択肢の1つを選択する際にランダムに(通常は "テストモード"フラグによってオンにされる)スケジューラを知っています。それで、テストを数回実行して、*すべての結果が正しいかどうかをチェックすることができます。しかし、これは本当の解決策ではありません。なぜなら、必要なラウンド数は決して分からないからです。 – rainer

+0

テスト用の提案は非常に便利ですが、実際の問題は、テストに失敗しない限り、コードを記述しないでください。この場合、仕様は意図的に柔軟性を残して、そのようなテストを書くことが不可能になります。これはいつも私がテスト駆動型のアプローチに悩まされているところですが、通常は良いテストを書くのはあまりにも怠惰だからではありません:-) –

答えて

1

この戦略は、多くの時間を動作します:

まず、エントロピーの任意の外部ソースを排除する(シングルスレッドを使用するようにスレッドプールを設定し;など事前にシードされたのPRNGに任意ののRNGをモック)次に、あなたを行使出力のすべての組み合わせを生成するために、繰り返しテスト、テスト中の機械への入力のみを変更:

from itertools import permutations 
def test_add_dependency(self): 
    """Tasks can be added with dependencies""" 
    for p in permutations("AB"): 
     self.done = [] 
     def test(id): 
      self.done.append("Test " + id) 
     s = Schedule(threads=1) 
     tasks = {id: Task("Test " + id, partial(test, id)) for id in "AB"} 
     s.add_task(tasks['A']) 
     s.add_task(tasks['B']) 
     s.add_dependency(tasks[p[0]], tasks[p[1]]) 
     s.run() 
     self.assertEqual(self.done, ["Test " + p[1], "Test " + p[0]]) 

Scheduleは、それはエントロピーの唯一の源であるとして、add_dependencyからの情報を使用するために失敗した場合は、このテストは失敗します(つまり、情報)が含まれています。

+0

良い点。私が心配しているのは、コードを書く前に、「バグを見つけなければならない」(依存関係の情報は無視される)テスト駆動開発アプローチです。しかし、私はこれらがブラックボックステストではなくユニットテストであるという事実を忘れています。だから私はスケジューラーの内部を模倣して、純粋に依存関係の処理に集中することができます。ありがとう! –

1

テスト目的のために、Scheduleクラスの異なる、確定的なバージョンを使用する(または既存のバージョンを決定的にするオプションを追加する)こともできますが、単体テストの目的を無効にする可能性があります。

もう1つの選択肢は、非決定論的結果のためのテストケースの記述を邪魔しないことです。一般的に


、しかし、あなたの質問への答えは...

は「偶然の」成功のこの種のを避けるために、筆記テストの方法はありますか?

...おそらく、「いいえ」、それ以外の場合は特に書き留めています。疑わしいテストケースを書くのを避けるために十分な注意を払う能力があり、最初にコードを書くことに注意を払った場合、おそらく単体テストは必要ありません。 ;-)

単体テストのポイントがコード内のバグを検出する場合は、単体テストのバグをどのように検出しますか?

ユニットテストのための 'meta'ユニットテストを書くことができますが、 'meta'ユニットテストのバグをどのように検出しますか?それで...

ユニットテストは役に立たないとは言えませんが、コードが「正しい」ことを「証明」するのに十分ではありません。実際には、ピアベースのコードレビューが、コードの欠陥を検出するためのより効果的な手段であることがわかりました。

+0

注文を強制するオプションをスケジューラに追加する確かに一つの選択肢になるでしょう。私はそれを考えなかった - ありがとう。 –

2

あなたは、不完全なデータのコレクションを見て、それに関する仮説が真であるかどうかを言うことを試みるすべての研究者の状況にいます。

実行ごとに結果が異なる場合、何度も再実行すると、統計を適用して動作しているかどうかを判断するサンプルが提供されます。しかし、一回の実行でも同様の結果が得られますが、別のバッチでは異なる結果が得られる場合、非決定論はプログラム自体の外部のイベントに依存します。理想的には、それらを制御して、悪いアルゴリズムをトリップする可能性を最大にする。

これは非決定論のコストです。統計に頼る必要があり、統計を正しく取得する必要があります。あなたは、いくつかの信頼レベルで仮説を受け入れることができる必要があり、帰無仮説も拒否しなければなりません。結果のばらつきを最大限にするには、サンプル数が少なくて済みます。さまざまなCPU負荷やIO割り込みを持っているか、またはランダムにスリープしているタスクをスケジュールしてください。

このようなスケジューラがどのような影響を受けるかを知るには、とにかく価値のあるテストを定義することをお勧めします。

1

テストを書く前に、テストする必要があるものを決定することをお勧めします。

上記のコードサンプルでは、​​実際のシーケンスがスケジューラの説明に従って決定的ではなくても、スケジューラによって特定の一連のタスクが生成されるため、テストでは実際には提供されませんコードについての保証:時には合格しない、時には合致しない、そして時には偶然になります。それらの位置については何も主張せずに結果のタスクの

一方、より多くの貴重な試験が存在(または不在)をアサートするかもしれない:「アレイの位置にある」対「セットである」

関連する問題