2017-12-09 2 views
2

Nach dem pytest documentation kann ich Kombinationen mehrerer parametrisierte Argumente erzeugen wie folgt:Wie markiert man bestimmte Kombinationen parametrisierter Pytest-Argumente?

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

Ich kann auch Markierungen auf einzelne Parameter als solche gelten:

@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 

Gibt es eine vernünftige Art und Weise zu kombinieren die beiden Methoden und wenden eine Markierung auf eine bestimmte Kombination von Parametern an? Kann ich zum Beispiel nur eine pytest.mark.xfail auf die test_foo Instanz anwenden, die mit x==0 und y==2 generiert wird?

Antwort

2

Der Ansatz, den ich bevorzuge, ist meine Argumente durch eine einfache Hilfsfunktion zu generieren. Werfen Sie einen Blick auf das folgende Beispiel:

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) 

Es ist immer noch ein einziges parametrize Dekorateur verwendet, aber es kommt ziemlich nah an, was Sie wollen, und ist leicht zu lesen und zu verstehen.


EDIT (1): Sie können die Hilfsfunktion tatsächlich als Generator implementieren. Die folgende funktioniert gut:

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): Da es in den Kommentaren gefragt wurde, kann dies tatsächlich für eine beliebige Anzahl von Parametern verallgemeinert werden und steht nicht im Widerspruch mit den Befestigungen. Überprüfen Sie das folgende Beispiel:

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) 

(Dank yield from, das ist Python 3.3 and above only.)

+0

Thanks @ s-m-e. Dies könnte für den beschriebenen Anwendungsfall funktionieren, obwohl der Nachteil ist, dass es nicht verallgemeinerbar ist, sagen wir in dem Fall, dass eine Fixture für "z" hinzugefügt wird –

+0

@WillAyd Glauben Sie das? Siehe Bearbeiten 2. –

Verwandte Themen