11

この質問と同様に、Nose にテスト (またはすべてのテスト) をn1 回実行してもらいたいのですが、並行し て実行することはできません。

プロジェクトには数百のテストがあります。単純な単体テストもあります。その他は、ある程度の並行性を備えた統合テストです。テストをデバッグするときに、テストをより強く「ヒット」したいことがよくあります。bash ループは機能しますが、多くの雑然とした出力になります。合格したテストごとに。選択したテストで何回かの試行で勝つ能力を持つことは、Nose に依頼するのは当然のことのように思えますが、ドキュメントのどこにも見つかりませんでした。

Nose にこれを実行させる最も簡単な方法は何ですか (bash ループ以外)?

4

5 に答える 5

17

ノーズテストを generator として書くことができ、ノーズは生成された各関数を実行します:

def check_something(arg):
    # some test ...

def test_something():
    for arg in some_sequence:
        yield (check_something, arg)

nodes-testconfigを使用すると、テスト実行の回数をコマンド ライン引数にすることができます。

from testconfig import config

# ...

def test_something():
    for n in range(int(config.get("runs", 1))):
        yield (check_something, arg)

たとえば、コマンドラインから呼び出すもの

$ nosetests --tc=runs:5

...複数回実行する場合。

別の方法として (ただし、nose-testconfig を使用しても)、デコレータを作成できます。

from functools import wraps
from testconfig import config

def multi(fn):
    @wraps(fn)
    def wrapper():
        for n in range(int(config.get("runs", 1))):
            fn()
    return wrapper

@multi
def test_something():
    # some test ...

そして、テストを異なるグループに分割したい場合は、それぞれに実行回数の独自のコマンド ライン引数を指定します。

from functools import wraps
from testconfig import config

def multi(cmd_line_arg):
    def wrap(fn):
        @wraps(fn)
        def wrapper():
            for n in range(int(config.get(cmd_line_arg, 1))):
                fn()
        return wrapper
    return wrap

@multi("foo")
def test_something():
    # some test ...

@multi("bar")
def test_something_else():
    # some test ...

次のように呼び出すことができます:

$ nosetests --tc=foo:3 --tc=bar:7
于 2012-11-28T18:18:40.390 に答える
3

私が最終的に使用した解決策は、shスクリプトrun_test.shを作成することです:

var=0
while $1; do
    ((var++))
    echo "*** RETRY $var"
done

使用法:

./run_test.sh "nosetests TestName"

テストは無限に実行されますが、最初のエラーで停止します。

于 2015-06-18T11:47:50.380 に答える
3

これを行うにはスクリプトを作成する必要がありますが、コマンドラインでテスト名を X 回繰り返すことができます。

nosetests testname testname testname testname testname testname testname

于 2014-05-30T00:25:24.733 に答える
2

1 つの方法は、テスト自体にあります。

これを変える:

class MyTest(unittest.TestCase):

  def test_once(self):
      ...

これに:

class MyTest(unittest.TestCase):

  def assert_once(self):
      ...

  def test_many(self):
      for _ in range(5):
          self.assert_once()
于 2012-11-28T18:19:16.377 に答える
-1

テストを複数回実行する理由があってはなりません。テストが決定論的であることが重要です (つまり、コードベースの状態が同じ場合、常に同じ結果が生成されます)。そうでない場合は、テストを複数回実行する代わりに、テストを再設計するか、および/またはになるようにコーディングします。

たとえば、テストが断続的に失敗する理由の 1 つは、テストとテスト対象コード (CUT) の間の競合状態です。この状況では、テストがアサートを開始する前に CUT が終了していることを「確認」するために、テストに大きな「ブードゥー スリープ」を追加するのが単純な対応です。

ただし、何らかの理由で CUT が遅い場合 (ハードウェアのパワー不足、ボックスのロード、データベースのビジー状態など) は散発的に失敗するため、エラーが発生しやすくなります。この場合のより良い解決策は、テストをスリープ状態にするのではなく、イベントを待機させることです。

イベントはあなたが選んだものなら何でもかまいません。使用できるイベントがすでに生成されている場合があります (たとえば、Javascript DOM イベント、Selenium テストで使用できる「pageRendered」の種類のイベント)。それ以外の場合は、CUT にコードを追加して、完了時のイベント (おそらく、アーキテクチャには、このようなイベントに関心のある他のコンポーネントが含まれています)。

ただし、多くの場合、CUT の実行が終了したかどうか (たとえば、出力ファイルはまだ存在するか) を検出し、そうでない場合は 50 ミリ秒スリープしてから再試行するように、テストを書き直す必要があります。最終的にはタイムアウトして失敗しますが、これは非常に長い時間 (たとえば、CUT の予想実行時間の 100 倍) の後でのみ実行してください。

もう 1 つのアプローチは、「onion/hexagonal/ports'n'adaptors」の原則を使用して CUT を設計することです。これは、ビジネス ロジックがすべての外部依存関係から解放されるべきであると主張します。これは、ネットワークやファイルシステムに触れることのない従来のミリ秒以下の単体テストを使用して、ビジネス ロジックをテストできることを意味します。これが完了すると、必要なエンド ツー エンドのシステム テストがはるかに少なくなります。これは、統合テストとしてのみ機能し、UI を通過するビジネス ロジックのすべての詳細とエッジ ケースを操作する必要がないためです。 . このアプローチは、CUT 設計の改善 (コンポーネント間の依存関係の削減)、テストの記述がはるかに簡単、テスト スイート全体の実行にかかる時間の大幅な短縮など、他の分野でも大きなメリットをもたらします。

上記のようなアプローチを使用すると、信頼性の低いテストの問題を完全に排除できます。テストだけでなく、コードベースと設計能力も改善するために、そうすることをお勧めします。

于 2012-11-28T18:20:57.267 に答える