2016-10-06 3 views
1

@ mark.incrementalの目的は、1つのテストが失敗した場合、その後のテストで失敗すると予想されることです。pytestテストクラスで@ mark.incrementalとmetafunc.parametrizeを使用する

しかし、これをパラメータ化と組み合わせて使用​​すると、私は望ましくない動作をします。

たとえば、この偽のコードの場合:

//conftest.py: 

def pytest_generate_tests(metafunc): 
    metafunc.parametrize("input", [True, False, None, False, True]) 

def pytest_runtest_makereport(item, call): 
    if "incremental" in item.keywords: 
     if call.excinfo is not None: 
      parent = item.parent 
      parent._previousfailed = item 

def pytest_runtest_setup(item): 
    if "incremental" in item.keywords: 
     previousfailed = getattr(item.parent, "_previousfailed", None) 
     if previousfailed is not None: 
      pytest.xfail("previous test failed (%s)" %previousfailed.name) 

//test.py: 
@pytest.mark.incremental 
class TestClass: 
    def test_input(self, input): 
     assert input is not None 
    def test_correct(self, input): 
     assert input==True 

私はテストクラスがTrueに

  • test_input、test_correct続い

  • を実行するために期待しますon True、

  • 次に、Falseの場合はtest_input、なしに(xfailed)test_correct、などなどが続く

代わりに、何が起こる

  • なしにtest_inputによってfolowed、偽のtest_correct続い

  • 、それはテストクラスです。

    • test_input o 、
    • は、その後、(test_corrects含む)xfailedとして
    • はその後、その時点からすべてをマークし、なしにtest_input走る
    • 、偽の上にnは真test_input実行されます。

    私が想定していることは、クラス内の関数を処理することよりもパラメータ化が優先されるということです。問題は、現在の状況ではクラスをインクリメンタルなものとして完全に役に立たないとマークするため、何らかの形でこの振る舞いをオーバーライドしたり、回避したりすることが可能かどうかです。

    (異なるパラメータで毎回、コピー&ペーストして何度もクラスのコードをこれに対処する唯一の方法です?考えは私に反発です)

  • 答えて

    1

    これに対する解決策はhttps://docs.pytest.org/en/latest/example/parametrize.htmlに記述されていますヘッダーの下にA quick port of “testscenarios”

    これはコードに記載されており、conftest.pyのコードは、テストクラスで変数scenariosを探しています。それは、変数を見つけると、それは、シナリオの各項目を反復処理し、テストの辞書ラベル付けするとid文字列を期待「argnamesを:argvalues」

    # content of conftest.py 
    def pytest_generate_tests(metafunc): 
        idlist = [] 
        argvalues = [] 
        for scenario in metafunc.cls.scenarios: 
         idlist.append(scenario[0]) 
         items = scenario[1].items() 
         argnames = [x[0] for x in items] 
         argvalues.append(([x[1] for x in items])) 
        metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class") 
    
    # content of test_scenarios.py 
    scenario1 = ('basic', {'attribute': 'value'}) 
    scenario2 = ('advanced', {'attribute': 'value2'}) 
    
    class TestSampleWithScenarios(object): 
        scenarios = [scenario1, scenario2] 
    
        def test_demo1(self, attribute): 
         assert isinstance(attribute, str) 
    
        def test_demo2(self, attribute): 
         assert isinstance(attribute, str) 
    

    あなたはまた、異なるデータ型を受け入れるように機能pytest_generate_testsを変更することができます入力。あなたは通常 @pytest.mark.parametrize("varname", varval_list) に渡すリストを持っている場合たとえば、あなたは次のように同じリストを使用することができます。

    # content of conftest.py 
    def pytest_generate_tests(metafunc): 
        idlist = [] 
        argvalues = [] 
        argnames = metafunc.cls.scenario_keys 
        for idx, scenario in enumerate(metafunc.cls.scenario_parameters): 
         idlist.append(str(idx)) 
         argvalues.append([scenario]) 
        metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class") 
    
    # content of test_scenarios.py 
    varval_list = [a, b, c, d] 
    class TestSampleWithScenarios(object): 
        scenario_parameters = varval_list 
        scenario_keys = ['varname'] 
    
        def test_demo1(self, attribute): 
         assert isinstance(attribute, str) 
    
        def test_demo2(self, attribute): 
         assert isinstance(attribute, str) 
    

    idが指定した自動生成された番号(あなたが何かを使用してそれを変更することができますになります)この実装では、複数のパラメータ化変数を扱うことはできませんので、それらを単一のリストでコンパイルする必要があります(または、pytest_generate_testsを処理してください)

    +0

    プレーンリンクの代わりにソリューションの主なポイントを追加してください。 – pirho

    +0

    このリンクは質問に答えるかもしれませんが、答えの本質的な部分をここに含めて参考にしてください。リンクされたページが変更された場合、リンクのみの回答は無効になります。 - [レビューから](レビュー/低品質の投稿/ 17864634) – nvoigt

    +0

    これは実際に関数の順番をうまく変更することはできますが、増分的な問題は解決しません。一度関数呼び出しが失敗すると、新しいシナリオを含め、その後の呼び出しにはxfailedとマークされます。まだ、これは答えの半分なので、私はもう半分に新しい質問をします – dWitty

    関連する問題