2017-12-09 7 views
2

pytest documentationによると、私は複数のパラメータ化引数の組み合わせを生成することができます。パラメータ化されたpytest引数の特定の組み合わせをマークするにはどうすればよいですか?次のように

@pytest.mark.parametrize("x", [0, 1]) 
@pytest.mark.parametrize("y", [2, 3]) 
def test_foo(x, y): 
    pass 

を私はまた、のような個々のパラメータにマークを適用することができます。

@pytest.mark.parametrize("test_input,expected", [ 
("3+5", 8), 
("2+4", 6), 
pytest.param("6*9", 42, 
      marks=pytest.mark.xfail), 
]) 
def test_eval(test_input, expected): 
    assert eval(test_input) == expected 

組み合わせるための合理的な方法はあります2つの方法論を組み合わせ、特定のパラメーターの組み合わせに印を付けるか?たとえば、x==0y==2で生成されるtest_fooインスタンスにのみpytest.mark.xfailを適用できますか?

答えて

2

私が好むアプローチは、単純なヘルパー関数を使用して引数を生成する方法です。次の例を見て:

import pytest 

def __get_param_xy__(x = [], y = [], xfail = []): # ugly demonstrator ... 
    out_list = [] 
    for xx in x: # this could be a clever list comprehension ... 
     for yy in y: # this one, too ... 
      out_tup = (xx, yy) 
      if out_tup in xfail: # the ones you expect to fail 
       out_tup = pytest.param(*out_tup, marks = pytest.mark.xfail) 
      out_list.append(out_tup) 
    return out_list 

@pytest.mark.parametrize('x,y', __get_param_xy__(
    x = [0, 1], 
    y = [2, 3], 
    xfail = [(0, 2)] 
    )) 
def test_foo(x, y): 
    assert not (x == 0 and y == 2) 

それはまだ単一parametrizeデコレータを使用していますが、それはあなたが望むものにかなり近い来て、読んで、理解しやすいです。


EDIT(1):実際には、ヘルパー関数をジェネレータとして実装できます。以下の作品だけで罰金:

def __get_param_xy__(x = [], y = [], xfail = []): # ugly generator ... 
    for xx in x: # this could be a clever list comprehension ... 
     for yy in y: # this one, too ... 
      out_tup = (xx, yy) 
      if out_tup in xfail: # the ones you expect to fail 
       out_tup = pytest.param(*out_tup, marks = pytest.mark.xfail) 
      yield out_tup 

EDIT(2):それはコメントで尋ねてきたので、これは実際のパラメータの任意の数のために一般化することができると備品と競合していません。次の例を確認してください:

import pytest 

class __mock_fixture_class__: 
    def __init__(self): 
     self.vector = [] 
    def do_something(self, parameter): 
     assert parameter != (0, 2) 
     self.vector.append(parameter) 
    def fin(self): 
     self.vector.clear() 

@pytest.fixture(scope = 'function') 
def mock_fixture(request): 
    mock_fixture_object = __mock_fixture_class__() 
    def __finalizer__(): 
     mock_fixture_object.fin() 
    request.addfinalizer(__finalizer__) 
    return mock_fixture_object 

def __get_param_general_generator__(*_, **kwargs): 
    xfail = kwargs.pop('xfail') if 'xfail' in kwargs.keys() else [] 
    arg_names = sorted(kwargs.keys()) 
    def _build_args_(in_tup =(), arg_index = 0): 
     for val in kwargs[arg_names[arg_index]]: 
      out_tup = (*in_tup, val) 
      if arg_index < len(arg_names) - 1: 
       yield from _build_args_(out_tup, arg_index + 1) 
      else: 
       if out_tup in xfail: 
        out_tup = pytest.param(*out_tup, marks = pytest.mark.xfail) 
       yield out_tup 
    return ','.join(arg_names), _build_args_() 

@pytest.mark.parametrize(*__get_param_general_generator__(
    x = [0, 1], 
    y = [2, 3], 
    xfail = [(0, 2)] 
    )) 
def test_foo_xy(mock_fixture, x, y): 
    mock_fixture.do_something((x, y)) 

@pytest.mark.parametrize(*__get_param_general_generator__(
    x = [0, 1], 
    y = [2, 3], 
    z = [0, 1, 2], 
    xfail = [(0, 2, 1)] 
    )) 
def test_bar_xyz(x, y, z): 
    assert not (x == 0 and y == 2 and z == 1) 

yield fromのおかげで、これはPython 3.3 and above onlyである。)、S-M-E @

+0

感謝を。欠点は一般的ではない、例えば "z"用のフィクスチャが追加された場合など。 –

+0

@WillAydそう思う?)編集2を参照してください。 –

関連する問題