web-dev-qa-db-ja.com

py.testの実行で各テストを複数回繰り返すにはどうすればよいですか?

選択した各py.testアイテムを任意の回数、順番に実行したい。
これを行うための標準のpy.testメカニズムが見当たりません。

pytest_collection_modifyitems()フックでこれを実行しようとしました。渡された項目のリストを変更して、各項目を複数回指定しました。テスト項目の最初の実行は期待どおりに機能しますが、それが私のコードにいくつかの問題を引き起こすようです。

さらに、さまざまなレポートコードのキーとしてid(アイテム)を使用するため、実行ごとに一意のテストアイテムオブジェクトを使用したいと思います。残念ながら、テスト項目を複製するpy.testコードが見つからず、copy.copy()が機能せず、copy.deepcopy()が例外を受け取ります。

誰かがテストを複数回実行するための戦略を提案できますか?

32

各テストを何度も実行するために、テストの生成時に各テストをプログラムでパラメーター化します。

最初に、パーサーオプションを追加しましょう(conftest.pyの1つに以下を含めます)。

def pytest_addoption(parser):
    parser.addoption('--repeat', action='store',
        help='Number of times to repeat each test')

次に、「pytest_generate_tests」フックを追加します。ここで魔法が起こります。

def pytest_generate_tests(metafunc):
    if metafunc.config.option.repeat is not None:
        count = int(metafunc.config.option.repeat)

        # We're going to duplicate these tests by parametrizing them,
        # which requires that each test has a fixture to accept the parameter.
        # We can add a new fixture like so:
        metafunc.fixturenames.append('tmp_ct')

        # Now we parametrize. This is what happens when we do e.g.,
        # @pytest.mark.parametrize('tmp_ct', range(count))
        # def test_foo(): pass
        metafunc.parametrize('tmp_ct', range(count))

繰り返しフラグなしで実行:

(env) $ py.test test.py -vv
============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 2 items 

test.py:4: test_1 PASSED
test.py:8: test_2 PASSED

=========================== 2 passed in 0.01 seconds ===========================

繰り返しフラグで実行:

(env) $ py.test test.py -vv --repeat 3
============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 6 items 

test.py:4: test_1[0] PASSED
test.py:4: test_1[1] PASSED
test.py:4: test_1[2] PASSED
test.py:8: test_2[0] PASSED
test.py:8: test_2[1] PASSED
test.py:8: test_2[2] PASSED

=========================== 6 passed in 0.01 seconds ===========================

参考文献:

13
Frank T

Pytestモジュール pytest-repeat はこの目的のために存在します。自分で機能を再実装するのではなく、可能な限りモジュールを使用することをお勧めします。

これを使用するには、pytest-repeatrequirements.txtまたはpip install pytest-repeatに追加してから、--count nを使用してテストを実行します。

37
jsj

1つの可能な戦略は、問題のテストをパラメーター化することですが、パラメーターを明示的に使用しません。

例えば:

@pytest.mark.parametrize('execution_number', range(5))
def run_multiple_times(execution_number):
    assert True

上記のテストは5回実行する必要があります。

パラメータ化のドキュメントを確認してください: https://pytest.org/latest/parametrize.html

32
Frank T

フランクTの提案に基づいて、私はpytest_generate_tests()コールアウトに非常に簡単な解決策を見つけました:

parser.addoption ('--count', default=1, type='int', metavar='count', help='Run each test the specified number of times')

def pytest_generate_tests (metafunc):
    for i in range (metafunc.config.option.count):
        metafunc.addcall()

ここで "py.test --count 5"を実行すると、各テストがテストセッションで5回実行されます。

また、既存のテストを変更する必要はありません。

フランクTに感謝します。

7

私がここで見たものに基づいており、pytest_collection_modifyitems、私の選択する方法は次のとおりです。 conftest.py

def pytest_addoption(parser):
    parser.addoption ('--count', default=1, type='int', metavar='count', help='Run each test the specified number of times')


def pytest_collection_modifyitems(session, config, items):
    count = config.option.count
    items[:] = items * count  # add each test multiple times
1
user7610